home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / fsconsist / fsconsistCache.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-27  |  76.0 KB  |  2,344 lines

  1. /* 
  2.  * fsCacheConsist.c --
  3.  *
  4.  *    Routines used to keep the file system caches consistent.  The
  5.  *    server maintains a list of client machines that have the file
  6.  *    open.  This list indicates how many opens per client, if the file
  7.  *    is being cached, and if the file is open for writing on a client.
  8.  *    The client list is updated when files are opened, closed, and removed.
  9.  *
  10.  *    SYNCHRONIZATION:  There are two classes of procedures here: those
  11.  *    that make call-backs to clients, and those that just examine the
  12.  *    client list.  All access to a client list is synchronized using
  13.  *    a monitor lock embedded in the consist structure.  Furthermore,
  14.  *    consistency actions are serialized by setting a flag during
  15.  *    call-backs (CONSIST_IN_PROGRESS).  There is a possible deadlock
  16.  *    if the monitor lock is held during a call-back because this
  17.  *    prevents a close operation from completing. (At close time the
  18.  *    client list is adjusted but no call-backs are made.  Also, the client
  19.  *    has its handle locked which blocks our call-back.)  Accordingly,
  20.  *    both the handle lock and the monitor lock are released during
  21.  *    a call-back.  The CONSIST_IN_PROGRESS flag is left on to prevent
  22.  *    other consistency actions during the call-back.
  23.  *
  24.  * Copyright 1986 Regents of the University of California.
  25.  * All rights reserved.
  26.  */
  27.  
  28. #ifndef lint
  29. static char rcsid[] = "$Header: /sprite/src/kernel/fsconsist/RCS/fsconsistCache.c,v 9.24 91/07/26 17:14:33 mendel Exp $ SPRITE (Berkeley)";
  30. #endif not lint
  31.  
  32. #include    <sprite.h>
  33. #include    <fs.h>
  34. #include    <fsutil.h>
  35. #include    <fsconsist.h>
  36. #include    <fscache.h>
  37. #include    <fsStat.h>
  38. #include    <fslcl.h>
  39. #include    <fsprefix.h>
  40. #include    <hash.h>
  41. #include    <vm.h>
  42. #include    <proc.h>
  43. #include    <sys.h>
  44. #include    <rpc.h>
  45. #include    <recov.h>
  46. #include    <timer.h>
  47. #include    <dbg.h>
  48. #include     <fsio.h>
  49. #include    <fsrmt.h>
  50. #include    <fsdm.h>
  51. #ifdef SOSP91
  52. #include    <sospRecord.h>
  53. #endif /* SOSP91 */
  54.  
  55. #include <stdio.h>
  56.  
  57. #define    LOCKPTR    (&consistPtr->lock)
  58.  
  59. Boolean    fsconsist_Debug = FALSE;
  60. Boolean    fsconsist_ClientCachingEnabled = TRUE;
  61. #ifdef CONSIST_DEBUG
  62. int    fsTraceConsistMinor = 2249;
  63. #endif /* CONSIST_DEBUG */
  64.  
  65. /*
  66.  * Flags for the Fsconsist_Info struct that's defined in fsInt.h
  67.  *
  68.  *    FS_CONSIST_IN_PROGRESS    Cache consistency is being performed on this
  69.  *                file.
  70.  *    FS_CONSIST_ERROR    There was an error during the cache 
  71.  *                consistency.
  72.  *    FS_CONSIST_TIMEOUT    There is a timeout setup for the consistency
  73.  *                actions.
  74.  */
  75. #define    FS_CONSIST_IN_PROGRESS    0x1
  76. #define    FS_CONSIST_ERROR    0x2
  77. #define FS_CONSIST_TIMEOUT    0x4
  78.  
  79. /*
  80.  * Clients have an (arbitrary) number of minutes to complete call-back
  81.  * actions before the server blows them off and lets an open operation
  82.  * complete.  This time has to be enough to let a client with a large
  83.  * main-memory cache writeback a large file.
  84.  */
  85. int fsconsist_TimeoutMinutes = 1;
  86.  
  87. /*
  88.  * Rpc to send when forcing a client to invalidate or write back a file.
  89.  */
  90.  
  91. typedef struct ConsistMsg {
  92.     Fs_FileID    fileID;        /* Which file to invalidate. */
  93.     int        flags;        /* One of the flags defined below. */
  94.     int        openTimeStamp;    /* Open that this rpc pertains to. */
  95.     int        version;    /* Version number of the file */
  96. } ConsistMsg;
  97.  
  98. /*
  99.  * Message sent when the client has completed the work requested by the server.
  100.  * This is actually the request part of the rpc transaction.
  101.  */
  102.  
  103. typedef struct ConsistReply {
  104.     Fs_FileID         fileID;
  105.     Fscache_Attributes    cachedAttr;
  106.     ReturnStatus    status;
  107. } ConsistReply;
  108.  
  109.  
  110. /*
  111.  * Structure used to keep track of outstanding cache consistency requests.
  112.  */
  113. typedef struct {
  114.     List_Links    links;
  115.     int        clientID;
  116.     int        flags;
  117. } ConsistMsgInfo;
  118.  
  119. /*
  120.  * Global time stamp.  A time stamp is returned to clients on each open
  121.  * and on cache consistency messages.  This way clients can detect races
  122.  * between open replies and consistency actions.
  123.  */
  124. static    int    openTimeStamp = 0;
  125.  
  126. /*
  127.  * Forward declarations.
  128.  */
  129. extern void StartConsistency _ARGS_((Fsconsist_Info *consistPtr, 
  130.             int clientID, int useFlags, Boolean *cacheablePtr));
  131. extern void UpdateList _ARGS_((Fsconsist_Info *consistPtr, int clientID, 
  132.         int useFlags, Boolean cacheable, int *openTimeStampPtr));
  133. extern ReturnStatus EndConsistency _ARGS_((Fsconsist_Info *consistPtr));
  134. extern void ConsistTimeoutIntr _ARGS_((Timer_Ticks time, ClientData data));
  135. extern void ConsistTimeout _ARGS_((ClientData data, 
  136.         Proc_CallInfo *callInfoPtr));
  137.  
  138. extern void ClientCommand _ARGS_((Fsconsist_Info *consistPtr,
  139.         Fsconsist_ClientInfo *clientPtr, int flags));
  140.  
  141. extern void ProcessConsist _ARGS_((ClientData data,Proc_CallInfo *callInfoPtr));
  142. extern void ProcessConsistReply _ARGS_((Fsconsist_Info *consistPtr, 
  143.         int clientID, ConsistReply *replyPtr));
  144.  
  145. extern char *ConsistType _ARGS_((int flags));
  146.  
  147.  
  148.  
  149. /*
  150.  * ----------------------------------------------------------------------------
  151.  *
  152.  * Fsconsist_Init --
  153.  *
  154.  *      Initialize the client use information for a file.  This is done
  155.  *    before adding any clients so it just resets all the fields.
  156.  *
  157.  * Results:
  158.  *    None.
  159.  *
  160.  * Side effects:
  161.  *    Reset the client use state..
  162.  *
  163.  * ----------------------------------------------------------------------------
  164.  *
  165.  */
  166. void
  167. Fsconsist_Init(consistPtr, hdrPtr)
  168.     register Fsconsist_Info *consistPtr;    /* State to initialize */
  169.     Fs_HandleHeader *hdrPtr;            /* Back pointer to handle */
  170. {
  171.     Sync_LockInitDynamic(&consistPtr->lock, "Fs:consistLock");
  172.     consistPtr->flags = 0;
  173.     consistPtr->lastWriter = -1;
  174.     consistPtr->openTimeStamp = 0;
  175.     consistPtr->hdrPtr = hdrPtr;
  176.     List_Init(&consistPtr->clientList);
  177.     List_Init(&consistPtr->msgList);
  178.     consistPtr->consistDone.waiting = 0;
  179.     consistPtr->repliesIn.waiting = 0;
  180. }
  181.  
  182. /*
  183.  * ----------------------------------------------------------------------------
  184.  *
  185.  * Fsconsist_SyncLockCleanup --
  186.  *
  187.  *      Clean up Sync_Lock tracing for the cache lock.
  188.  *
  189.  * Results:
  190.  *    None.
  191.  *
  192.  * Side effects:
  193.  *    As above.
  194.  *
  195.  * ----------------------------------------------------------------------------
  196.  *
  197.  */
  198. /*ARGSUSED*/
  199. void
  200. Fsconsist_SyncLockCleanup(consistPtr)
  201.     Fsconsist_Info *consistPtr;    /* State to initialize */
  202. {
  203.     Sync_LockClear(&consistPtr->lock);
  204. }
  205.  
  206. /*
  207.  * ----------------------------------------------------------------------------
  208.  *
  209.  * Fsconsist_MappedConsistency --
  210.  *
  211.  *    Take action to ensure that everything is consistent for a
  212.  *    file that is being mapped.
  213.  *
  214.  * Results:
  215.  *    SUCCESS or FS_FILE_BUSY.
  216.  *
  217.  * Side effects:
  218.  *    Issues cache consistency messages.
  219.  *
  220.  * ----------------------------------------------------------------------------
  221.  *
  222.  */
  223. /*ARGSUSED*/
  224. ENTRY ReturnStatus
  225. Fsconsist_MappedConsistency(handlePtr, clientID, isMapped)
  226.     Fsio_FileIOHandle     *handlePtr;    /* File to check consistency of. */
  227.     int         clientID;    /* ID of the host doing the map. */
  228.     int            isMapped;    /* 1 if file is being mapped. */
  229. {
  230. #ifdef notdef
  231.     int                    cacheable;    /* Dummy. */
  232.     register Fsconsist_ClientInfo    *clientPtr;
  233.     register Fsconsist_Info        *consistPtr = &handlePtr->consist;
  234.     ReturnStatus            status;
  235.  
  236.     printf("Fsconsist_MappedConsistency: updating consistency (a)\n");
  237.     LOCK_MONITOR;
  238.  
  239.     printf("Fsconsist_MappedConsistency: updating consistency (b)\n");
  240.     StartConsistency(consistPtr, clientID, (int)(isMapped ? FS_MAP : 0),
  241.         &cacheable);
  242.  
  243.     printf("Fsconsist_MappedConsistency: updating consistency (c)\n");
  244.     LIST_FORALL(&consistPtr->clientList, (List_Links *)clientPtr) {
  245.     if (clientPtr->clientID == clientID) {
  246.         clientPtr->mapped = isMapped ? TRUE : FALSE;
  247.     }
  248.     }
  249.  
  250.     printf("Fsconsist_MappedConsistency: updating consistency (d)\n");
  251.     status = EndConsistency(consistPtr);
  252.     printf("Fsconsist_MappedConsistency: updating consistency (e)\n");
  253.  
  254.     UNLOCK_MONITOR;
  255.     return(status);
  256. #endif
  257.     return SUCCESS;
  258. }
  259.  
  260. /*
  261.  * ----------------------------------------------------------------------------
  262.  *
  263.  * Fsconsist_FileConsistency --
  264.  *
  265.  *    Take action to ensure that the caches are consistent for this
  266.  *    file.  This checks against use conflicts and will return an
  267.  *    non-SUCCESS status if the open should fail.  Otherwise this
  268.  *    makes call-backs to other clients to keep caches consistent.
  269.  *
  270.  * Results:
  271.  *    SUCCESS or FS_FILE_BUSY.  Also, *cacheablePtr set to TRUE if the
  272.  *    file is cacheable on the client.  *openTimeStampPtr is set to the
  273.  *    next open time stamp on the file.  Clients use this timeStamp
  274.  *    to catch races between open replies, which have the next timeStamp,
  275.  *    and consistency messages from other opens happening
  276.  *    at about the same time, which have the current timeStamp.
  277.  *
  278.  * Side effects:
  279.  *    Issues cache consistency messages and adds the client to the
  280.  *    list of clients of the file.
  281.  *    The handle is unlocked before Fsconsist_FileConsistency is called.
  282.  *
  283.  * ----------------------------------------------------------------------------
  284.  *
  285.  */
  286. ENTRY ReturnStatus
  287. Fsconsist_FileConsistency(handlePtr, clientID, useFlags, cacheablePtr,
  288.     openTimeStampPtr)
  289.     Fsio_FileIOHandle *handlePtr;    /* File to check consistency of. */
  290.     int         clientID;    /* ID of the host doing the open */
  291.     register int     useFlags;    /* useFlags from the open call */
  292.     Boolean        *cacheablePtr;    /* TRUE if file is cacheable. */
  293.     int            *openTimeStampPtr;/* Timestamp of open.  Used by clients
  294.                      * to catch races between open replies
  295.                      * and cache consistency messages */
  296. {
  297.     register Fsconsist_Info *consistPtr = &handlePtr->consist;
  298.     ReturnStatus status;
  299.  
  300.     LOCK_MONITOR;
  301.  
  302.     /*
  303.      * Go through the list of other clients using the file checking
  304.      * for conflicts and issuing cache consistency messages.
  305.      */
  306.     StartConsistency(consistPtr, clientID, useFlags, cacheablePtr);
  307.     /*
  308.      * Add ourselves to the list of clients using the file.
  309.      */
  310.     UpdateList(consistPtr, clientID, useFlags, *cacheablePtr,
  311.         openTimeStampPtr);
  312.     /*
  313.      * Now that we are all set up, and have told all the other clients
  314.      * using the file what they have to do, we wait for them to finish.
  315.      */
  316.     status = EndConsistency(consistPtr);
  317.     UNLOCK_MONITOR;
  318.     return(status);
  319. }
  320.  
  321. /*
  322.  * ----------------------------------------------------------------------------
  323.  *
  324.  * StartConsistency --
  325.  *
  326.  *      Initiate cache consistency action on a file.  This decides if the
  327.  *    client can cache the file, and then makes call-backs to other
  328.  *    clients so that caches stay consistent.  EndConsistency
  329.  *    should be called later to wait for the client replies.
  330.  *
  331.  * Results:
  332.  *    *cacheablePtr set to TRUE if the file is cacheable.   *fileBusyPtr
  333.  *    is set to FS_FILE_BUSY if the file is either being opened for execution
  334.  *    and it is already open for writing or vice versa.
  335.  *
  336.  * Side effects:
  337.  *    Sets the FS_CONSIST_IN_PROGRESS flag and makes call-backs to
  338.  *    clients.  The flag is cleared if the call-backs can't be made.
  339.  *
  340.  * ----------------------------------------------------------------------------
  341.  *
  342.  */
  343.  
  344. INTERNAL void
  345. StartConsistency(consistPtr, clientID, useFlags, cacheablePtr)
  346.     Fsconsist_Info    *consistPtr;    /* File's consistency state. */
  347.     int            clientID;    /* ID of host opening the file */
  348.     int            useFlags;    /* Indicates how they are using it */
  349.     Boolean        *cacheablePtr;    /* Return, TRUE if client can cache */
  350. {
  351.     register Fsconsist_ClientInfo *clientPtr;
  352.     register Fsconsist_ClientInfo *nextClientPtr;
  353.     register Fs_ConsistStats *statPtr = &fs_Stats.consist;
  354.     register Fs_MigStats *migStatPtr = &fs_Stats.mig;
  355.     register int openForWriting = useFlags & FS_WRITE;
  356.     register Boolean cacheable;
  357.     Boolean countMigration;    /* Set if we're supposed to increment a
  358.                    counter for the type of consistency
  359.                    performed, and cleared once the increment
  360.                    is done. */
  361.     int clients = 0;
  362.     int notCaching = 0;
  363.     int writebackFlags;
  364.  
  365.     /*
  366.      * Make sure that noone else is in the middle of performing cache
  367.      * consistency on this file.
  368.      */
  369.     while (consistPtr->flags & FS_CONSIST_IN_PROGRESS) {
  370.     (void) Sync_Wait(&consistPtr->consistDone, FALSE);
  371.     }
  372.     consistPtr->flags = FS_CONSIST_IN_PROGRESS;
  373.  
  374.     /*
  375.      * Determine cacheability of the file.  Note the system-wide switch
  376.      * to disable client caching.  There are other special cases that
  377.      * are not cached:
  378.      *  1. Swap files are not cached on clients.
  379.      *    2. Non-files, (dirs, links) are not cacheable so we don't have to
  380.      *       worry about keeping them consistent.  (This could be done.)
  381.      *  3. Files that are being concurrently write-shared are not cached.
  382.      *     This includes one writer and one or more readers on other hosts,
  383.      *       and writers on multiple hosts.
  384.      */
  385.     cacheable = fsconsist_ClientCachingEnabled;
  386.     if (useFlags & FS_MIGRATING) {
  387.     countMigration = 1;
  388.     writebackFlags = FSCONSIST_MIGRATION;
  389.     } else {
  390.     countMigration = 0;
  391.     writebackFlags = 0;
  392.     }
  393.     if ((useFlags & FS_SWAP) && (clientID != rpc_SpriteID)) {
  394.     cacheable = FALSE;
  395.     statPtr->swap++;
  396.     } else if (((Fsio_FileIOHandle *)consistPtr->hdrPtr)->descPtr->fileType
  397.             != FS_FILE) {
  398.     cacheable = FALSE;
  399.     statPtr->nonFiles++;
  400.     } else if (useFlags & FS_MAP) {
  401.     cacheable = FALSE;
  402.     }
  403.     if (cacheable) {
  404.     LIST_FORALL(&consistPtr->clientList, (List_Links *)clientPtr) {
  405.         if (clientPtr->mapped) {
  406.         cacheable = FALSE;
  407.         goto done;
  408.         }
  409.         if (clientPtr->clientID != clientID) {
  410.         if ((clientPtr->use.write > 0) ||
  411.             ((clientPtr->use.ref > 0) && openForWriting)) {
  412.             cacheable = FALSE;
  413.             goto done;
  414.         }
  415.         }
  416.     }
  417.     } else {
  418.     countMigration = FALSE;
  419.     }
  420. done:
  421. #ifdef CONSIST_DEBUG
  422.     if (fsTraceConsistMinor == consistPtr->hdrPtr->fileID.minor) {
  423.     printf("File <%d,%d> version %d start consist w/ use 0x%x, %s\n",
  424.         consistPtr->hdrPtr->fileID.major,
  425.         consistPtr->hdrPtr->fileID.minor,
  426.         ((Fsio_FileIOHandle *)consistPtr->hdrPtr)->cacheInfo.version,
  427.         useFlags, (cacheable ? "cacheable" : "not cacheable"));
  428.     }
  429. #endif /* CONSIST_DEBUG */
  430.     /*
  431.      * Now that we know the cacheable state of the file, check the use
  432.      * by other clients, perhaps sending them cache consistency
  433.      * messages.  For each message we send out (the client replies
  434.      * right-away without actually doing anything yet) ClientCommand
  435.      * adds an entry to the consistInfo's message list.  Note also that
  436.      * the current client list entry can get removed as side effects of
  437.      * a call-back so we can't use a simple LIST_FOR_ALL here.
  438.      *
  439.      * Record statistics for both regular opens and migrations.  Migrations
  440.      * are really a subset of regular opens since only some cases can occur.
  441.      */
  442.     statPtr->files++;
  443.     if (countMigration) {
  444.     migStatPtr->consistActions++;
  445.     }
  446.     nextClientPtr = (Fsconsist_ClientInfo *)List_First(&consistPtr->clientList);
  447.     while (!List_IsAtEnd(&consistPtr->clientList, (List_Links *)nextClientPtr)){
  448.     clientPtr = nextClientPtr;
  449.     clientPtr->locked = FALSE;
  450.     nextClientPtr = (Fsconsist_ClientInfo *)List_Next((List_Links *)clientPtr);
  451.     /*
  452.      * Hang onto the next client element across calls to ClientCommand,
  453.      * which releases the consistency lock and may allow client list
  454.      * deletions due to garbage collection.
  455.      */
  456.     if (!List_IsAtEnd(&consistPtr->clientList,(List_Links *)nextClientPtr)){
  457.         nextClientPtr->locked = TRUE;
  458.     }
  459.     if (clientPtr->clientID == clientID) {
  460.         /*
  461.          * Don't call back to the client doing the open.  That can
  462.          * cause deadlock.  Instead, that client takes care of its
  463.          * own cache via the Fscache_UpdateFile procedure.
  464.          */
  465.         if (clientPtr->clientID == consistPtr->lastWriter) {
  466.         statPtr->writeCaching++;
  467.         } else if (clientPtr->use.ref > 0 && clientPtr->cached) {
  468.         statPtr->readCachingMyself++;
  469.         }
  470.         continue;
  471.     }
  472. #ifdef CONSIST_DEBUG
  473.     if (fsTraceConsistMinor == consistPtr->hdrPtr->fileID.minor) {
  474.         printf("Client %d, %s, use %d write %d\n",
  475.             clientPtr->clientID,
  476.             (clientPtr->cached ? "caching" : "not caching"),
  477.             clientPtr->use.ref, clientPtr->use.write);
  478.     }
  479. #endif /* CONSIST_DEBUG */
  480.     clients++;
  481.     if (!clientPtr->cached) {
  482.         /*
  483.          * Case 1, the other client isn't caching the file. Do nothing.
  484.          */
  485.         notCaching++;
  486.     } else if (cacheable) {
  487.         if (consistPtr->lastWriter != clientPtr->clientID) {
  488.         /*
  489.          * Case 2, the other client is caching and it's ok.
  490.          */
  491.         statPtr->readCachingOther++;
  492.         if (countMigration) {
  493.             /*
  494.              * Already caching for reading -- this migration can't
  495.              * change that.
  496.              */
  497.             migStatPtr->readOnlyFiles++;
  498.             countMigration = 0;
  499.         }
  500.         } else if (consistPtr->lastWriter == clientID) {
  501.         /*
  502.          * Case 3, the last writer is now opening for reading.
  503.          * Its dirty cache is ok.  (This case is trapped out above.)
  504.          */
  505.         statPtr->writeCaching++;
  506.         } else {
  507.         int mode;
  508.         /*
  509.          * Case 4, the last writer needs to give us back the
  510.          * dirty blocks so the opening client will get good data.
  511.          * In the case of migration, it is possible for a writable
  512.          * file to be migrated to another host while still being
  513.          * cacheable.  In that case the old client doesn't have
  514.          * any more references to the file and can't use its cached
  515.          * blocks for it anyway.  Since the version number doesn't
  516.          * get incremented due to migration we have to invalidate
  517.          * at migration time.
  518.          */
  519.         mode = FSCONSIST_WRITE_BACK_BLOCKS | writebackFlags;
  520.         if (openForWriting) {
  521.             mode |= FSCONSIST_INVALIDATE_BLOCKS;
  522.         }
  523.         ClientCommand(consistPtr, clientPtr, mode);
  524. #ifdef SOSP91
  525.         SOSP_ADD_CONSIST_ACTION_TRACE(clientID, clientPtr->clientID, consistPtr->hdrPtr->fileID, mode);
  526. #endif SOSP91
  527.         statPtr->writeBack++;
  528.         if (countMigration) {
  529.             migStatPtr->cacheWritableFiles++;
  530.             countMigration = 0;
  531.         }
  532.         }
  533.     } else {
  534.         if ((clientPtr->use.write == 0) && (clientPtr->use.ref > 0)) {
  535.         /*
  536.          * Case 5, another reader needs to stop caching.
  537.          */
  538.         ClientCommand(consistPtr, clientPtr,
  539.                     FSCONSIST_INVALIDATE_BLOCKS);
  540. #ifdef SOSP91
  541.         SOSP_ADD_CONSIST_ACTION_TRACE(clientID, clientPtr->clientID, consistPtr->hdrPtr->fileID, FSCONSIST_INVALIDATE_BLOCKS);
  542. #endif SOSP91
  543.         statPtr->readInvalidate++;
  544.         } else if (clientPtr->use.write > 0) {
  545.         /*
  546.          * Case 6, the writer needs to stop caching and give
  547.          * us back its dirty blocks.
  548.          */
  549.         ClientCommand(consistPtr, clientPtr,
  550.                   FSCONSIST_WRITE_BACK_BLOCKS |
  551.                   FSCONSIST_INVALIDATE_BLOCKS | writebackFlags);
  552. #ifdef SOSP91
  553.         SOSP_ADD_CONSIST_ACTION_TRACE(clientID, clientPtr->clientID, consistPtr->hdrPtr->fileID, FSCONSIST_WRITE_BACK_BLOCKS | FSCONSIST_INVALIDATE_BLOCKS);
  554. #endif SOSP91
  555.         statPtr->writeInvalidate++;
  556.         }
  557.         if (countMigration) {
  558.         migStatPtr->cacheToUncacheFiles++;
  559.         countMigration = 0;
  560.         }
  561.     }
  562.     }
  563.     if (cacheable) {
  564.     statPtr->cacheable++;
  565.     if (countMigration) {
  566.         if (notCaching == clients) {
  567.         migStatPtr->uncacheToCacheFiles++;
  568.         } else {
  569.         migStatPtr->readOnlyFiles++;
  570.         }
  571.     }
  572.     } else {
  573.     statPtr->uncacheable++;
  574.     if (countMigration) {
  575.         migStatPtr->uncacheableFiles++;
  576.     }
  577.     }
  578.     statPtr->clients += clients;
  579.     statPtr->notCaching += notCaching;
  580.     *cacheablePtr = cacheable;
  581. }
  582.  
  583. /*
  584.  * ----------------------------------------------------------------------------
  585.  *
  586.  * UpdateList --
  587.  *
  588.  *    Update the state of the client that is using one of our files.
  589.  *    A timestamp is generated for return to the client so it can
  590.  *    catch races between the open return message and cache consistency
  591.  *    messages associated with this file.
  592.  *
  593.  * Results:
  594.  *    The timestamp.
  595.  *
  596.  * Side effects:
  597.  *    The version number is incremented when open for writing.  The
  598.  *    lastWriter is remembered when opening for writing.  Use counts
  599.  *    are kept to reflect the clients use of the file.  Finally,
  600.  *    client list entries for hosts no longer using or caching the
  601.  *    file are deleted.
  602.  *
  603.  * ----------------------------------------------------------------------------
  604.  */
  605.  
  606. INTERNAL void
  607. UpdateList(consistPtr, clientID, useFlags, cacheable, openTimeStampPtr)
  608.     register Fsconsist_Info *consistPtr;/* Consistency state for the file. */
  609.     int            clientID;    /* ID of client using the file */
  610.     int            useFlags;    /* FS_READ|FS_WRITE|FS_EXECUTE */
  611.     Boolean        cacheable;    /* TRUE if client is caching the file */
  612.     int            *openTimeStampPtr;/* Generated for the client so it can
  613.                      * catch races between the return from
  614.                      * this open and other cache messages */
  615. {
  616.     register Fsconsist_ClientInfo *clientPtr;    /* State for other clients */
  617.  
  618.     /*
  619.      * Add the client to the I/O handle client list.
  620.      */
  621.     clientPtr = Fsconsist_IOClientOpen(&consistPtr->clientList, clientID,
  622.         useFlags, cacheable);
  623.  
  624.     if (cacheable && (useFlags & FS_WRITE)) {
  625.     consistPtr->lastWriter = clientID;
  626.     }
  627. #ifdef CONSIST_DEBUG
  628.     if (fsTraceConsistMinor == consistPtr->hdrPtr->fileID.minor) {
  629.     printf("UpdateList: client %d %s, last writer %d\n",
  630.         clientID, (clientPtr->cached ? "caching" : "not caching"),
  631.         consistPtr->lastWriter);
  632.     }
  633. #endif /* CONSIST_DEBUG */
  634.     /*
  635.      * Return a time stamp for the open.  This timestamp is used by clients
  636.      * to catch races between the reply message for an open, and a cache
  637.      * consistency message generated from a different open happening at
  638.      * about the same time.
  639.      */
  640.     if (openTimeStampPtr != (int *)NIL) {
  641.     openTimeStamp++;
  642.     *openTimeStampPtr =
  643.         consistPtr->openTimeStamp =
  644.         clientPtr->openTimeStamp = openTimeStamp;
  645.     } else {
  646.     consistPtr->openTimeStamp = clientPtr->openTimeStamp = 0;
  647.     }
  648. }
  649.  
  650.  
  651. /*
  652.  * ----------------------------------------------------------------------------
  653.  *
  654.  * EndConsistency --
  655.  *    Wait for cache consistency actions to complete.
  656.  *
  657.  * Results:
  658.  *    SUCCESS or FS_NO_DISK_SPACE.  We have to abort an open if a client
  659.  *    cannot write back its cache in response to a consistency message.
  660.  *    This only happens if the disk is full.  If the client is down we
  661.  *    won't wait for it.  If it is not really down we treat it as
  662.  *    down and will abort its attempt to re-open later.
  663.  *
  664.  * Side effects:
  665.  *    Notifies the consistDone condition to allow someone else to
  666.  *    open the file.  Clears the FS_CONSIST_IN_PROGRES flag.
  667.  *
  668.  * ----------------------------------------------------------------------------
  669.  *
  670.  */
  671.  
  672. INTERNAL ReturnStatus
  673. EndConsistency(consistPtr)
  674.     Fsconsist_Info    *consistPtr;
  675. {
  676.     register ReturnStatus status;
  677.     Timer_QueueElement timeout;
  678.  
  679.     /*
  680.      * Set up a timeout in case a flakey client can't complete
  681.      * its consistency actions.  We pick an arbitrary "long" interval
  682.      * and just abort after that.  A more complex solution would be
  683.      * to re-iterate what ever high level operation we are doing.
  684.      */
  685.     timeout.routine = ConsistTimeoutIntr;
  686.     timeout.interval = timer_IntOneMinute * fsconsist_TimeoutMinutes;
  687.     timeout.clientData = (ClientData)consistPtr;
  688.     consistPtr->flags |= FS_CONSIST_TIMEOUT;
  689.     Timer_ScheduleRoutine(&timeout, TRUE);
  690.  
  691.     while (!List_IsEmpty(&consistPtr->msgList)) {
  692.     (void) Sync_Wait(&consistPtr->repliesIn, FALSE);
  693.     }
  694.     if (consistPtr->flags & FS_CONSIST_TIMEOUT) {
  695.     (void)Timer_DescheduleRoutine(&timeout);
  696.     consistPtr->flags &= ~FS_CONSIST_TIMEOUT;
  697.     }
  698.     if (consistPtr->flags & FS_CONSIST_ERROR) {
  699.     /*
  700.      * The only reason consistency actions fail altogether is when
  701.      * a client can't do a writeback because there isn't enough
  702.      * disk space here.  Crashed clients don't matter.
  703.      */
  704.     status = FS_NO_DISK_SPACE;
  705.     } else {
  706.     status = SUCCESS;
  707.     }
  708.     consistPtr->flags = 0;
  709.     Sync_Broadcast(&consistPtr->consistDone);
  710.     return(status);
  711. }
  712.  
  713. /*
  714.  *----------------------------------------------------------------------
  715.  *
  716.  * ConsistTimeoutIntr --
  717.  *
  718.  *    Routine called at timer-interrupt time if a client has not
  719.  *    completed consistency actions.  This turns around and does
  720.  *    a Proc_CallFunc to invoke ConsistTimeout at process level.
  721.  *    ConsistTimeout prints a warning and removes the information
  722.  *    about the now aborted consistency request so that the higher-level
  723.  *    operation can complete.
  724.  *
  725.  * Results:
  726.  *    None.
  727.  *
  728.  * Side effects:
  729.  *    Triggers a call to ConsistTimeout, which in turn erases the
  730.  *    consistPtr->msgList and notifies the consistPtr->repliesIn condition.
  731.  *
  732.  *----------------------------------------------------------------------
  733.  */
  734. /*ARGSUSED*/
  735. void
  736. ConsistTimeoutIntr(time, data)
  737.     Timer_Ticks time;    /* The time we timed out at. */
  738.     ClientData data;    /* A pointer to a Fsconsist_Info */
  739. {
  740.     Fsconsist_Info *consistPtr = (Fsconsist_Info *)data;
  741.  
  742.     consistPtr->flags &= ~FS_CONSIST_TIMEOUT;
  743.     Proc_CallFunc(ConsistTimeout, (ClientData)consistPtr, 0);
  744. }
  745.  
  746. void
  747. ConsistTimeout(data, callInfoPtr)
  748.     ClientData        data;    /* A pointer to a Fsconsist_Info */
  749.     Proc_CallInfo    *callInfoPtr;
  750. {
  751.     Fsconsist_Info *consistPtr = (Fsconsist_Info *)data;
  752.     ConsistMsgInfo *msgPtr;
  753.     int ref, write, exec;
  754.  
  755.     LOCK_MONITOR;
  756.     while (!List_IsEmpty(&consistPtr->msgList)) {
  757.     msgPtr = (ConsistMsgInfo *)List_First(&consistPtr->msgList);
  758.  
  759.     printf("ConsistTimeout (%d minutes) client %d %s file <%d,%d> \"%s\"\n",
  760.         fsconsist_TimeoutMinutes,
  761.         msgPtr->clientID, ConsistType(msgPtr->flags),
  762.         consistPtr->hdrPtr->fileID.major,
  763.         consistPtr->hdrPtr->fileID.minor,
  764.         Fsutil_HandleName(consistPtr->hdrPtr));
  765.  
  766.     Fsconsist_IOClientKill(&consistPtr->clientList, msgPtr->clientID,
  767.             &ref, &write, &exec);
  768.     printf("\tClient state killed: %d refs %d write %d exec\n",
  769.             ref, write, exec);
  770.  
  771.     if (msgPtr->clientID == consistPtr->lastWriter) {
  772.         consistPtr->lastWriter = -1;
  773.     }
  774.     List_Remove((List_Links *)msgPtr);
  775.     free((Address)msgPtr);
  776.     }
  777.     Sync_Broadcast(&consistPtr->repliesIn);
  778.     callInfoPtr->interval = 0;    /* No more invocations, please */
  779.     UNLOCK_MONITOR;
  780. }
  781.  
  782.  
  783. /*
  784.  * ----------------------------------------------------------------------------
  785.  *
  786.  * Fsconsist_ReopenClient --
  787.  *
  788.  *    Conflict checking has already been done for the re-open, and this
  789.  *    routine updates global use counts and the client list so that
  790.  *    regular opens know the file is being used.  This is called with
  791.  *    the handle locked and it also grabs the consistency monitor lock
  792.  *    to update the client list.
  793.  *    Consistency call-backs are made    later by Fsconsist_ReopenConsistency.
  794.  *
  795.  * Results:
  796.  *    None.
  797.  *
  798.  * Side effects:
  799.  *    Updates the global use counts of the file, the last writer of
  800.  *    the file, and the client list entry for this client.  Note that
  801.  *    by updating the lastWriter here we may cause a call-back to
  802.  *    the re-opening client during Fsconsist_ReopenConsistency.  This is the
  803.  *    best we can do if another client has slipped in and opened
  804.  *    for reading already.
  805.  *
  806.  * ----------------------------------------------------------------------------
  807.  */
  808. ENTRY void
  809. Fsconsist_ReopenClient(handlePtr, clientID, use, haveDirtyBlocks)
  810.     Fsio_FileIOHandle    *handlePtr;    /* Should be LOCKED. */
  811.     int            clientID;    /* The client who is opening the file.*/
  812.     Fsio_UseCounts        use;        /* Clients usage of the file */
  813.     Boolean         haveDirtyBlocks;/* TRUE if client expects it to be
  814.                      * cacheable because it has
  815.                      * outstanding dirty blocks. */
  816. {
  817.     register Fsconsist_Info    *consistPtr = &handlePtr->consist;
  818.     register Fsconsist_ClientInfo    *clientPtr;
  819.     Boolean            found;
  820.  
  821.     LOCK_MONITOR;
  822.  
  823.     found = FALSE;
  824.     LIST_FORALL(&(consistPtr->clientList), (List_Links *)clientPtr) {
  825.     if (clientPtr->clientID == clientID) {
  826.         found = TRUE;
  827.         handlePtr->use.ref   += use.ref   - clientPtr->use.ref;
  828.         handlePtr->use.write += use.write - clientPtr->use.write;
  829.         handlePtr->use.exec  += use.exec  - clientPtr->use.exec;
  830.         clientPtr->use = use;
  831.         clientPtr->cached = haveDirtyBlocks;
  832.         if ((handlePtr->use.ref < 0) || (handlePtr->use.write < 0) ||
  833.             (handlePtr->use.exec < 0)) {
  834.         panic("Fsconsist_ReopenClient: client %d ref %d write %d exec %d\n" ,
  835.             clientID,
  836.             handlePtr->use.ref, handlePtr->use.write,
  837.             handlePtr->use.exec);
  838.         }
  839.     } else if ((clientPtr->use.ref > 0) && haveDirtyBlocks) {
  840.         /*
  841.          * Oops, another client is reading this file but the re-opening
  842.          * client has dirty blocks for it.  We've already checked the
  843.          * version number so we know another client isn't writing.
  844.          * We allow this conflict to happen - the regular cache
  845.          * consistency routines will tell the reading client to
  846.          * stop caching, and the writing client will write-back
  847.          * its blocks as soon as possible.  This leaves a window
  848.          * for inconsistent reads, but the outstanding dirty blocks
  849.          * are not lost.
  850.          */
  851.         printf("FsReopenHandle: file \"%s\" <%d,%d>: client %d has dirty blocks, but client %d is using\n",
  852.         Fsutil_HandleName(handlePtr),
  853.         handlePtr->hdr.fileID.major, handlePtr->hdr.fileID.minor,
  854.         clientID, clientPtr->clientID);
  855.     }
  856.     }
  857. #ifdef CONSIST_DEBUG
  858.     if (fsTraceConsistMinor == handlePtr->hdr.fileID.minor) {
  859.     printf("Fsconsist_ReopenClient %d, use %d write %d, %s, last writer %d\n",
  860.         clientID, use.ref, use.write, (found ? "found" : "not found"),
  861.         consistPtr->lastWriter);
  862.     }
  863. #endif /* notdef */
  864.  
  865.     if (!found) {
  866.     INSERT_CLIENT(&consistPtr->clientList, clientPtr, clientID);
  867.     clientPtr->use = use;
  868.     clientPtr->cached = haveDirtyBlocks;
  869.  
  870.     handlePtr->use.ref   += use.ref;
  871.     handlePtr->use.write += use.write;
  872.     handlePtr->use.exec  += use.exec;
  873.     }
  874.     if (haveDirtyBlocks) {
  875.     if (consistPtr->lastWriter != -1 &&
  876.         consistPtr->lastWriter != clientID) {
  877.         /*
  878.          * Version number checking should have prevented this.
  879.          */
  880.         printf("FsReopenHandle: file \"%s\" <%d,%d>: Client %d with dirty blocks not last writer %d\n",
  881.         Fsutil_HandleName(handlePtr),
  882.         handlePtr->hdr.fileID.major, handlePtr->hdr.fileID.minor,
  883.         clientID, consistPtr->lastWriter);
  884.     } else {
  885.         consistPtr->lastWriter = clientID;
  886.     }
  887.     } else if (consistPtr->lastWriter == clientID) {
  888.     consistPtr->lastWriter = -1;
  889.     }
  890.     UNLOCK_MONITOR;
  891. }
  892.  
  893. /*
  894.  * ----------------------------------------------------------------------------
  895.  *
  896.  * Fsconsist_ReopenConsistency --
  897.  *
  898.  *    Perform cache consistency actions for a file that the client had 
  899.  *    open before we crashed.  This is similar to regular cache consistency,
  900.  *    except that the client list has already been updated by
  901.  *    Fsconsist_ReopenClient.  This can result in a call-back to the
  902.  *    re-opening client asking to write back its version of the file.
  903.  *
  904.  * Results:
  905.  *    TRUE if could provide the cacheability expected, FALSE otherwise.
  906.  *
  907.  * Side effects:
  908.  *    *cacheablePtr is TRUE if the file is to be cached by the client.
  909.  *    *openTimeStampPtr is set for use by clients.  They keep this timestamp
  910.  *    in order to catch races between the return from their open request
  911.  *    (which we are part of) and cache consistency messages resulting from
  912.  *    opens occuring at about the same time.
  913.  *
  914.  * ----------------------------------------------------------------------------
  915.  */
  916. ENTRY ReturnStatus
  917. Fsconsist_ReopenConsistency(handlePtr, clientID, use, swap, cacheablePtr,
  918.     openTimeStampPtr)
  919.     Fsio_FileIOHandle    *handlePtr;    /* Should be UNLOCKED. */
  920.     int            clientID;    /* The client who is opening the file.*/
  921.     Fsio_UseCounts    use;        /* Clients usage of the file */
  922.     int            swap;        /* 0 or FS_SWAP to indicate swap file.*/
  923.     Boolean         *cacheablePtr;    /* IN: TRUE if client expects it to be
  924.                      * cacheable, i.e. has dirty blocks.
  925.                      * OUT: Cacheability of the file. */
  926.     int            *openTimeStampPtr; /* Place to return a timestamp for 
  927.                      * this open.*/
  928. {
  929.     int                useFlags;
  930.     Boolean            cacheable;
  931.     ReturnStatus        status;
  932.     register Fsconsist_Info    *consistPtr = &handlePtr->consist;
  933.     register Fsconsist_ClientInfo    *clientPtr;
  934.  
  935.     LOCK_MONITOR;
  936.  
  937.     useFlags = swap;
  938.     if (use.ref > use.write + use.exec) {
  939.     useFlags |= FS_READ;
  940.     }
  941.     if (use.write > 0 || *cacheablePtr) {
  942.     useFlags |= FS_WRITE;
  943.     }
  944.     if (use.exec > 0) {
  945.     useFlags |= FS_EXECUTE;
  946.     }
  947.  
  948.     if (useFlags == 0) {
  949.     /*
  950.      * The client isn't using the file anymore so clean up state.
  951.      */
  952.     LIST_FORALL(&(consistPtr->clientList), (List_Links *)clientPtr) {
  953.         if (clientPtr->clientID == clientID) {
  954.         REMOVE_CLIENT(clientPtr);
  955.         break;
  956.         }
  957.     }
  958.     *openTimeStampPtr = consistPtr->openTimeStamp;
  959.     *cacheablePtr = FALSE;
  960.     status = SUCCESS;
  961.     } else {
  962.     StartConsistency(consistPtr, clientID, useFlags, &cacheable);
  963.  
  964.     /*
  965.      * Get a new openTimeStamp so the client can detect races between
  966.      * the reopen return and consistency messages generated by other
  967.      * opens happening right now (or real soon).
  968.      * FIX ME.  The file version number should be used instead.
  969.      */
  970.     openTimeStamp++;
  971.     *openTimeStampPtr = consistPtr->openTimeStamp = openTimeStamp;
  972.     /*
  973.      * Mark the client as caching or not.
  974.      */
  975.     *cacheablePtr = cacheable;
  976.     if ((useFlags & FS_WRITE) && cacheable) {
  977.         consistPtr->lastWriter = clientID;
  978.     }
  979.     /*
  980.      * We are careful to search for the client list entry again
  981.      * because it might go away during concurrent operations.
  982.      */
  983.     LIST_FORALL(&consistPtr->clientList, (List_Links *)clientPtr) {
  984.         if (clientPtr->clientID == clientID) {
  985.         clientPtr->openTimeStamp = openTimeStamp;
  986.         clientPtr->cached = cacheable;
  987.         break;
  988.         }
  989.     }
  990.     /*
  991.      * Wait for cache consistency call-backs to complete.
  992.      */
  993.     status = EndConsistency(consistPtr);
  994.     }
  995.     UNLOCK_MONITOR;
  996.     return(status);
  997. }
  998.  
  999. /*
  1000.  * ----------------------------------------------------------------------------
  1001.  *
  1002.  * Fsconsist_MigrateConsistency --
  1003.  *
  1004.  *    Shift the references on a file from one client to another.  If
  1005.  *    the stream to this handle is not shared across network this
  1006.  *    is done by first removing the useCounts due to the srcClient,
  1007.  *    and them performing the regular cache consistency algorithm as
  1008.  *    if the dstClient is opening the file.  If the stream is shared
  1009.  *    things are more complicated.  We must not close the original
  1010.  *    client until all stream references to its I/O handle have migrated,
  1011.  *    and we must be careful to not add too many references to the
  1012.  *    new client.
  1013.  *
  1014.  * Results:
  1015.  *    SUCCESS, unless there is a cache consistency conflict detected.
  1016.  *
  1017.  * Side effects:
  1018.  *    The HANDLE RETURNS UNLOCKED.  Also, full-fledged cache consistency
  1019.  *    actions are taken.
  1020.  *
  1021.  * ----------------------------------------------------------------------------
  1022.  */
  1023.  
  1024. ENTRY ReturnStatus
  1025. Fsconsist_MigrateConsistency(handlePtr, srcClientID, dstClientID, useFlags,
  1026.     closeSrc, cacheablePtr, openTimeStampPtr)
  1027.     Fsio_FileIOHandle    *handlePtr;    /* Needs to be UNLOCKED  */
  1028.     int            srcClientID;    /* ID of client using the file */
  1029.     int            dstClientID;    /* ID of client using the file */
  1030.     int            useFlags;    /* FS_READ|FS_WRITE|FS_EXECUTE
  1031.                      * FS_RMT_SHARED if shared now.
  1032.                      * FS_NEW_STREAM if dstClientID is
  1033.                      * getting stream for first time.
  1034.                      * FS_MIGRATED_FILE is set to tell
  1035.                      * the low-level consistency routines
  1036.                      * to record statistics. */
  1037.     Boolean        closeSrc;    /* TRUE if should close source client.
  1038.                      * Set by Fsio_StreamMigClient */
  1039.     Boolean        *cacheablePtr;    /* Return - Cachability of file */
  1040.     int            *openTimeStampPtr;/* Generated for the client so it can
  1041.                      * catch races between the return from
  1042.                      * this open and other cache messages */
  1043. {
  1044.     register Fsconsist_Info *consistPtr = &handlePtr->consist;
  1045.     Boolean            cache;
  1046.     register    ReturnStatus    status;
  1047.  
  1048.     LOCK_MONITOR;
  1049.  
  1050.     cache = (srcClientID == consistPtr->lastWriter);
  1051.  
  1052.     if (closeSrc) {
  1053.     /*
  1054.      * Remove references due to the original client so it doesn't confuse
  1055.      * the regular cache consistency algorithm.  Note that this call
  1056.      * doesn't disturb the last writer state so any dirty blocks on
  1057.      * the old client will get handled properly.
  1058.      */
  1059.     if (!Fsconsist_IOClientClose(&consistPtr->clientList, srcClientID,
  1060.                      useFlags, &cache)) {
  1061.         printf("Fsconsist_MigrateConsistency, srcClient %d unknown for %s %s <%d,%d>\n",
  1062.         srcClientID,
  1063.         Fsutil_FileTypeToString(handlePtr->hdr.fileID.type),
  1064.         Fsutil_HandleName(handlePtr),
  1065.         handlePtr->hdr.fileID.major, handlePtr->hdr.fileID.minor);
  1066.     }
  1067. #ifdef SOSP91
  1068.     SOSP_ADD_CONSIST_CHANGE_TRACE(srcClientID, consistPtr->hdrPtr->fileID, SOSP_CLOSE, cache);
  1069. #endif SOSP91
  1070.     }
  1071.     /*
  1072.      * The rest of this is like regular cache consistency.
  1073.      */
  1074.  
  1075.     StartConsistency(consistPtr, dstClientID, useFlags | FS_MIGRATING,
  1076.              cacheablePtr);
  1077. #ifdef SOSP91
  1078.     if (*cacheablePtr) {
  1079.     SOSP_ADD_CONSIST_CHANGE_TRACE(dstClientID, consistPtr->hdrPtr->fileID,
  1080.         SOSP_OPEN, useFlags & FS_WRITE);
  1081.     }
  1082. #endif /* SOSP91 */
  1083.     if (useFlags & FS_NEW_STREAM) {
  1084.     /*
  1085.      * The client is getting the stream to this I/O handle for
  1086.      * the first time so we should add it as a client.  We are
  1087.      * careful about this because there is only one reference to
  1088.      * the I/O handle per client per stream. 
  1089.      */
  1090.     UpdateList(consistPtr, dstClientID, useFlags, *cacheablePtr,
  1091.             openTimeStampPtr);
  1092.     }
  1093.     status = EndConsistency(consistPtr);
  1094.  
  1095.     UNLOCK_MONITOR;
  1096.     return(status);
  1097. }
  1098.  
  1099.  
  1100. /*
  1101.  * ----------------------------------------------------------------------------
  1102.  *
  1103.  * Fsconsist_GetClientAttrs --
  1104.  *
  1105.  *    This does call-backs to clients to flush back cached attributes.
  1106.  *    Files that are being executed are treated as a special case.  They
  1107.  *    are not being written so we, the server, have the right size and
  1108.  *    modify time.  Instead of getting access times from clients (there
  1109.  *    could be lots and lots) we just return a flag that says the
  1110.  *    file is being executed.  Our caller will presumably use the
  1111.  *    the current time for the access time in this case.
  1112.  *
  1113.  * Results:
  1114.  *    *isExecedPtr set to TRUE if the file is being executed.
  1115.  *
  1116.  * Side effects:
  1117.  *      RPC's may be done to clients using the file to tell them to write
  1118.  *    back their cached attributes.
  1119.  *    This unlocks the handle while waiting for clients, but
  1120.  *    re-locks it before returning.
  1121.  *
  1122.  * ----------------------------------------------------------------------------
  1123.  */
  1124. ENTRY void
  1125. Fsconsist_GetClientAttrs(handlePtr, clientID, isExecedPtr)
  1126.     register Fsio_FileIOHandle *handlePtr;
  1127.     int            clientID;    /* The client who is doing the stat.*/
  1128.     Boolean        *isExecedPtr;    /* TRUE if file is being executed.
  1129.                      * Our caller will use the current
  1130.                      * time for the access time in this
  1131.                      * case */
  1132. {
  1133.     register Boolean        isExeced = FALSE;
  1134.     register Fsconsist_Info    *consistPtr = &handlePtr->consist;
  1135.     register Fsconsist_ClientInfo    *clientPtr;
  1136.     register Fsconsist_ClientInfo    *nextClientPtr;
  1137.  
  1138.     /*
  1139.      * Unlock the handle so other operations on the file can proceed while
  1140.      * we probe around the network for the most up-to-date attributes.
  1141.      * Otherwise the following deadlock is possible:
  1142.      * Client 1 does a get attributes about the same time client 2 does
  1143.      * a close.  Client 2 has its handle locked during the close, but we
  1144.      * will be calling back to it to get its attributes.  Our callback can't
  1145.      * start until client 2 unlocks its handle, but it can't unlock it's
  1146.      * handle until the close finishes.  The close can't finish because
  1147.      * it is blocked here on the locked handle.
  1148.      */
  1149.  
  1150.     Fsutil_HandleUnlock(handlePtr);
  1151.     LOCK_MONITOR;
  1152.  
  1153.     /*
  1154.      * Make sure that noone else is in the middle of performing cache
  1155.      * consistency on this handle.  If so wait until they are done.
  1156.      */
  1157.     while (consistPtr->flags & FS_CONSIST_IN_PROGRESS) {
  1158.     (void) Sync_Wait(&consistPtr->consistDone, FALSE);
  1159.     }
  1160.     consistPtr->flags = FS_CONSIST_IN_PROGRESS;
  1161.  
  1162.     /*
  1163.      * Go through the set of clients using the file and see if they
  1164.      * are caching attributes.
  1165.      */
  1166.     nextClientPtr = (Fsconsist_ClientInfo *)List_First(&consistPtr->clientList);
  1167.     while (!List_IsAtEnd(&consistPtr->clientList, (List_Links *)nextClientPtr)){
  1168.     clientPtr = nextClientPtr;
  1169.     clientPtr->locked = FALSE;;
  1170.     nextClientPtr = (Fsconsist_ClientInfo *)List_Next((List_Links *)clientPtr);
  1171.     /*
  1172.      * Hang onto the next client list element across calls to ClientCommand,
  1173.      * which releases the consistency lock and allows list deletions.
  1174.      */
  1175.     if (!List_IsAtEnd(&consistPtr->clientList,(List_Links *)nextClientPtr)){
  1176.         nextClientPtr->locked = TRUE;
  1177.     }
  1178.     if (clientPtr->use.exec > 0) {
  1179.         isExeced = TRUE;
  1180.     }
  1181.     if ((clientPtr->cached) && (clientPtr->use.ref > 0)) {
  1182.         if ((clientPtr->clientID != clientID) &&
  1183.         (clientPtr->use.exec == 0)) {
  1184.         /*
  1185.          * Don't call back to our caller because it will check
  1186.          * its own attributes later.  Also, don't send rpcs to
  1187.          * clients executing files.  For these clients we just
  1188.          * set the access time to the current time.  This
  1189.          * is an optimization to not make stating of binaries
  1190.          * abysmally slow.
  1191.          */
  1192.  
  1193. #ifdef SOSP91
  1194.         /* what do I do about attribute call-backs? */
  1195.         SOSP_ADD_CONSIST_ACTION_TRACE(clientID, clientPtr->clientID, consistPtr->hdrPtr->fileID, FSCONSIST_WRITE_BACK_ATTRS);
  1196. #endif SOSP91
  1197.         ClientCommand(consistPtr, clientPtr, FSCONSIST_WRITE_BACK_ATTRS);
  1198.         }
  1199.     }
  1200.     }
  1201.     /*
  1202.      * Now that we are all set up, and have told all the other clients using
  1203.      * the file what they have to do, we wait for them to finish.
  1204.      */
  1205.     (void)EndConsistency(consistPtr);
  1206.  
  1207.     *isExecedPtr = isExeced;
  1208.     UNLOCK_MONITOR;
  1209.     Fsutil_HandleLock(handlePtr);
  1210. }
  1211.  
  1212. /*
  1213.  * ----------------------------------------------------------------------------
  1214.  *
  1215.  * Fsconsist_Close --
  1216.  *
  1217.  *    A thin layer on top of Fsconsist_IOClientClose that also cleans up
  1218.  *    the last writer of a file.
  1219.  *
  1220.  * Results:
  1221.  *    TRUE if there was a record that the client was using the file.
  1222.  *    This is used to trap out invalid closes.  Also, *wasCachedPtr
  1223.  *    is set to TRUE if the file (in particular, its attributes) was
  1224.  *    cached on the client.
  1225.  *
  1226.  * Side effects:
  1227.  *    The client list entry is removed.  If the client was
  1228.  *    the last writer but has no dirty blocks (as indicated by the flags)
  1229.  *    then the last writer field of the consist info is cleared.
  1230.  *
  1231.  * ----------------------------------------------------------------------------
  1232.  *
  1233.  */
  1234. ENTRY Boolean
  1235. Fsconsist_Close(consistPtr, clientID, flags, wasCachedPtr)
  1236.     register Fsconsist_Info *consistPtr;    /* Handle of file being closed */
  1237.     int            clientID;    /* Host ID of client that had it open */
  1238.     register int    flags;        /* Flags from the stream. */
  1239.     Boolean        *wasCachedPtr;    /* TRUE upon return if the client was
  1240.                      * caching (attributes) of the file. */
  1241. {
  1242.     LOCK_MONITOR;
  1243.  
  1244.     *wasCachedPtr = (consistPtr->lastWriter == clientID);
  1245. #ifdef CONSIST_DEBUG
  1246.     if (consistPtr->hdrPtr->fileID.minor == fsTraceConsistMinor) {
  1247.     printf("ConsistClose: closing client %d, lastwriter %d\n",
  1248.             clientID, consistPtr->lastWriter);
  1249.     }
  1250. #endif CONSIST_DEBUG
  1251.     if (!Fsconsist_IOClientClose(&consistPtr->clientList, clientID, flags,
  1252.              wasCachedPtr)) {
  1253.     UNLOCK_MONITOR;
  1254.     return(FALSE);
  1255.     }
  1256.  
  1257.     UNLOCK_MONITOR;
  1258.     return(TRUE);
  1259. }
  1260.  
  1261.  
  1262. /*
  1263.  * ----------------------------------------------------------------------------
  1264.  *
  1265.  * Fsconsist_NumClients --
  1266.  *
  1267.  *    Returns the number of clients in the client list for a file.
  1268.  *    Called to see if it's ok to scavenge the file handle.
  1269.  *
  1270.  * Results:
  1271.  *    The number of clients in the client list.
  1272.  *
  1273.  * Side effects:
  1274.  *    Unused client list entries are cleaned up.  We only need to remember
  1275.  *    clients that are actively using the file or who have dirty blocks
  1276.  *    because they are the last writer.
  1277.  *
  1278.  * ----------------------------------------------------------------------------
  1279.  *
  1280.  */
  1281.  
  1282. #ifdef SOSP91
  1283. ENTRY int
  1284. Fsconsist_NumClients(consistPtr, numReadPtr, numWritePtr)
  1285.     register Fsconsist_Info *consistPtr;   /* Handle of file being closed */
  1286.     int    *numReadPtr;        /* Number of clients reading the file. */
  1287.     int    *numWritePtr;        /* Number of clients writing the file. */
  1288.  
  1289. #else
  1290.  
  1291. ENTRY int
  1292. Fsconsist_NumClients(consistPtr)
  1293.     register Fsconsist_Info *consistPtr;    /* Handle of file being closed */
  1294.  
  1295. #endif
  1296.  
  1297. {
  1298.     register int numClients = 0;
  1299.     register Fsconsist_ClientInfo *clientPtr;
  1300.     register Fsconsist_ClientInfo *nextClientPtr;
  1301.  
  1302. #ifdef SOSP91
  1303.     int    numWrite = 0;
  1304.     int numRead = 0;
  1305. #endif
  1306.  
  1307.  
  1308.     LOCK_MONITOR;
  1309.  
  1310.     if (consistPtr->flags & FS_CONSIST_IN_PROGRESS) {
  1311.     /*
  1312.      * Not safe to mess with list during consistency.
  1313.      */
  1314.     numClients = 1;
  1315.     goto exit;
  1316.     }
  1317.     nextClientPtr = (Fsconsist_ClientInfo *)List_First(&consistPtr->clientList);
  1318.     while (!List_IsAtEnd(&consistPtr->clientList, (List_Links *)nextClientPtr)){
  1319.     clientPtr = nextClientPtr;
  1320.     nextClientPtr = (Fsconsist_ClientInfo *)List_Next((List_Links *)clientPtr);
  1321.     /*
  1322.      * Nuke the client list entry if the client isn't using the file now,
  1323.      * and it isn't a remote client holding dirty blocks,
  1324.      * and this element isn't locked by another process doing consistency.
  1325.      */
  1326.     if (clientPtr->use.ref == 0 &&
  1327.         ((clientPtr->clientID == rpc_SpriteID) || 
  1328.          (clientPtr->clientID != consistPtr->lastWriter)) &&
  1329.         !clientPtr->locked) {
  1330.         REMOVE_CLIENT(clientPtr);
  1331.     } else {
  1332.         numClients++;
  1333. #ifdef SOSP91
  1334.         if (clientPtr->use.write > 0) {
  1335.         numWrite++;
  1336.         } 
  1337.         if (clientPtr->use.ref - clientPtr->use.write > 0) {
  1338.         numRead++;
  1339.         }
  1340. #endif
  1341.  
  1342.     }
  1343.     }
  1344. exit:
  1345. #ifdef SOSP91
  1346.     if (numWritePtr != (int *) NIL) {
  1347.     *numWritePtr = numWrite;
  1348.     }
  1349.     if (numReadPtr != (int *) NIL) {
  1350.     *numReadPtr = numRead;
  1351.     }
  1352. #endif
  1353.     UNLOCK_MONITOR;
  1354.     return(numClients);
  1355. }
  1356.  
  1357.  
  1358. /*
  1359.  * ----------------------------------------------------------------------------
  1360.  *
  1361.  * Fsconsist_DeleteLastWriter --
  1362.  *
  1363.  *    Remove the last writer from the consistency list.  This is called
  1364.  *    from the write rpc stub when the last block of a file comes
  1365.  *    in from a remote client.
  1366.  *
  1367.  * Results:
  1368.  *    None.
  1369.  *
  1370.  * Side effects:
  1371.  *    Removes the client list entry for the last writer if the last
  1372.  *    writer is no longer using the file.
  1373.  *
  1374.  * ----------------------------------------------------------------------------
  1375.  *
  1376.  */
  1377. ENTRY void
  1378. Fsconsist_DeleteLastWriter(consistPtr, clientID)
  1379.     Fsconsist_Info *consistPtr;
  1380.     int        clientID;
  1381. {
  1382.     register    Fsconsist_ClientInfo    *clientPtr;
  1383.  
  1384.     LOCK_MONITOR;
  1385.  
  1386.     if (consistPtr->flags & FS_CONSIST_IN_PROGRESS) {
  1387.     /*
  1388.      * Not safe to mess with the list during consistency.  We are called
  1389.      * from Fsrmt_RpcWrite on the client's last block, but we will
  1390.      * delete the last writer in ProcessConsistReply if the write-back
  1391.      * is forced as part of cache consistency.
  1392.      */
  1393.     UNLOCK_MONITOR;
  1394.     return;
  1395.     }
  1396.     LIST_FORALL(&consistPtr->clientList, (List_Links *) clientPtr) {
  1397.     if (clientPtr->clientID == clientID) {
  1398.         if (clientPtr->use.ref == 0 &&
  1399.         consistPtr->lastWriter == clientID) {
  1400. #ifdef CONSIST_DEBUG
  1401.         if (consistPtr->hdrPtr->fileID.minor == fsTraceConsistMinor) {
  1402.             printf("Fsconsist_DeleteLastWriter <%d,%d> host %d\n",
  1403.             consistPtr->hdrPtr->fileID.major,
  1404.             consistPtr->hdrPtr->fileID.minor, clientID);
  1405.         }
  1406. #endif CONSIST_DEBUG
  1407.         if (!clientPtr->locked) {
  1408.             REMOVE_CLIENT(clientPtr);
  1409.         }
  1410.         consistPtr->lastWriter = -1;
  1411.         break;
  1412.         }
  1413.     }
  1414.     }
  1415.     UNLOCK_MONITOR;
  1416. }
  1417.  
  1418. /*
  1419.  * ----------------------------------------------------------------------------
  1420.  *
  1421.  * Fsconsist_ClientRemoveCallback --
  1422.  *
  1423.  *      Called when a file is deleted.  Send an rpc to the client who has
  1424.  *      dirty blocks cached telling it to delete them from its cache.
  1425.  *    We may have forgotten about clients with clean blocks so we can't
  1426.  *    call them back.  Instead we depend on the version number being
  1427.  *    incremented to catch old blocks left in caches.  There are two
  1428.  *    reasons to tell the last writer - first, it prevents needless
  1429.  *    write-backs, which consumes our CPU, and it is nice to the client
  1430.  *    because it can make room in its cache by deleting the file.
  1431.  *
  1432.  * Results:
  1433.  *    None.
  1434.  *
  1435.  * Side effects:
  1436.  *    Any remotely cached dirty data is invalidated.
  1437.  *    All the entries in the client list are deleted.
  1438.  *
  1439.  * ----------------------------------------------------------------------------
  1440.  *
  1441.  */
  1442. ENTRY void
  1443. Fsconsist_ClientRemoveCallback(consistPtr, clientID)
  1444.     Fsconsist_Info *consistPtr;    /* File to check */
  1445.     int        clientID;    /* Client who is removing the file.  This
  1446.                  * host is not contacted via call-back.
  1447.                  * Instead, the current RPC (close) should
  1448.                  * return FS_FILE_REMOVED.  Note, a callback
  1449.                  * is made during a remove-by-name. */
  1450. {
  1451.     register    Fsconsist_ClientInfo    *clientPtr;
  1452.     int                curClientID;
  1453.  
  1454.     Fsutil_HandleUnlock(consistPtr->hdrPtr);
  1455.  
  1456.     LOCK_MONITOR;
  1457.  
  1458.     while (consistPtr->flags & FS_CONSIST_IN_PROGRESS) {
  1459.     (void) Sync_Wait(&consistPtr->consistDone, FALSE);
  1460.     }
  1461.     consistPtr->flags = FS_CONSIST_IN_PROGRESS;
  1462.  
  1463.     /*
  1464.      * Loop through the list notifying clients and deleting client elements.
  1465.      */
  1466.     while (!List_IsEmpty((List_Links *)&consistPtr->clientList)) {
  1467.     clientPtr = (Fsconsist_ClientInfo *)
  1468.             List_First((List_Links *) &consistPtr->clientList);
  1469.     curClientID = clientPtr->clientID;
  1470.     if (clientPtr->use.ref > 0) {
  1471.         printf("Fsconsist_ClientRemoveCallback: Client %d using removed file <%s>\n",
  1472.         curClientID, Fsutil_HandleName(consistPtr->hdrPtr));
  1473.     } else if (consistPtr->lastWriter != -1) {
  1474.         if (clientPtr->clientID != consistPtr->lastWriter) {
  1475.         printf("Fsconsist_ClientRemoveCallback: \"%s\" <%d,%d> client %d not last writer (%d).\n",
  1476.             Fsutil_HandleName(consistPtr->hdrPtr),
  1477.             consistPtr->hdrPtr->fileID.major,
  1478.             consistPtr->hdrPtr->fileID.minor,
  1479.             clientPtr->clientID, consistPtr->lastWriter);
  1480.         } else if (clientPtr->clientID != clientID) {
  1481.         /*
  1482.          * Tell the client caching the file to remove it from its cache.
  1483.          * This should only be the last writer as we are called only
  1484.          * when it is truely time to remove the file.
  1485.          */
  1486.         ClientCommand(consistPtr, clientPtr, FSCONSIST_DELETE_FILE);
  1487. #ifdef SOSP91
  1488.         SOSP_ADD_CONSIST_ACTION_TRACE(clientID, clientPtr->clientID, consistPtr->hdrPtr->fileID, FSCONSIST_DELETE_FILE);
  1489. #endif SOSP91
  1490.         (void)EndConsistency(consistPtr);
  1491.         }
  1492.     }
  1493.     /*
  1494.      * We have to check carefully that the client element is still
  1495.      * here because it may already be removed by ClientKill.
  1496.      */
  1497.     LIST_FORALL((List_Links *)&consistPtr->clientList,
  1498.             (List_Links *)clientPtr) {
  1499.         if (clientPtr->clientID == curClientID) {
  1500.         REMOVE_CLIENT(clientPtr);
  1501.         break;
  1502.         }
  1503.     }
  1504.     }
  1505.     consistPtr->flags = 0;
  1506.     consistPtr->lastWriter = -1;
  1507.     UNLOCK_MONITOR;
  1508.     Fsutil_HandleLock(consistPtr->hdrPtr);
  1509. }
  1510.  
  1511. /*
  1512.  * ----------------------------------------------------------------------------
  1513.  *
  1514.  * Fsconsist_Kill --
  1515.  *
  1516.  *    Find and remove the given client in the list for the handle.  The
  1517.  *    number of client references, writers, and executers is returned
  1518.  *    so our caller can clean up the reference counts in the handle.
  1519.  *
  1520.  * Results:
  1521.  *    *inUsePtr set to TRUE if the client has the file open, *writingPtr
  1522.  *    set to TRUE if the client has the file open for writing, and 
  1523.  *    *executingPtr set to TRUE if the client has the file open for
  1524.  *    execution.
  1525.  *    
  1526.  * Side effects:
  1527.  *    If this client was the last writer for the file then the last
  1528.  *    writer field in the handle is set to -1.
  1529.  *
  1530.  * ----------------------------------------------------------------------------
  1531.  *
  1532.  */
  1533. ENTRY void
  1534. Fsconsist_Kill(consistPtr, clientID, refPtr, writePtr, execPtr)
  1535.     Fsconsist_Info *consistPtr;    /* Consistency state from which to remove
  1536.                  * the client. */
  1537.     int        clientID;    /* Client to delete. */
  1538.     int        *refPtr;    /* Number of times client has file open. */
  1539.     int        *writePtr;    /* Number of times client is writing file. */
  1540.     int        *execPtr;    /* Number of times clients is executing file.*/
  1541. {
  1542.     register ConsistMsgInfo     *msgPtr;
  1543.  
  1544.     LOCK_MONITOR;
  1545.  
  1546.     Fsconsist_IOClientKill(&consistPtr->clientList, clientID, refPtr, writePtr,
  1547.             execPtr);
  1548.  
  1549.     if (consistPtr->lastWriter == clientID) {
  1550.     consistPtr->lastWriter = -1;
  1551.     }
  1552.     /*
  1553.      * Remove the client from the list of clients involved in a cache
  1554.      * consistency action so we don't hang on the dead client.
  1555.      */
  1556.     LIST_FORALL(&(consistPtr->msgList), (List_Links *) msgPtr) {
  1557.     if (msgPtr->clientID == clientID) {
  1558.         List_Remove((List_Links *) msgPtr);
  1559.         free((Address) msgPtr);
  1560.         Sync_Broadcast(&consistPtr->repliesIn);
  1561.         break;
  1562.     }
  1563.     }
  1564.  
  1565.     UNLOCK_MONITOR;
  1566. }
  1567.  
  1568. /*
  1569.  *----------------------------------------------------------------------------
  1570.  *
  1571.  * Fsconsist_GetAllDirtyBlocks --
  1572.  *
  1573.  *    Retrieve dirty blocks from all clients that have files open on the
  1574.  *    given domain.  This is called when a disk is being detached.  We
  1575.  *    have to get any outstanding data before taking the disk off-line.
  1576.  *
  1577.  * Results:
  1578.  *    None.
  1579.  *
  1580.  * Side effects:
  1581.  *    None.
  1582.  *
  1583.  *----------------------------------------------------------------------------
  1584.  */
  1585. void
  1586. Fsconsist_GetAllDirtyBlocks(domain, invalidate)
  1587.     int        domain;        /* Domain to get dirty blocks for. */
  1588.     Boolean    invalidate;    /* Remove file from cache after getting blocks
  1589.                  * back. */
  1590. {
  1591.     Hash_Search                hashSearch;
  1592.     register    Fs_HandleHeader        *hdrPtr;
  1593.  
  1594.     Hash_StartSearch(&hashSearch);
  1595.     for (hdrPtr = Fsutil_GetNextHandle(&hashSearch);
  1596.      hdrPtr != (Fs_HandleHeader *) NIL;
  1597.          hdrPtr = Fsutil_GetNextHandle(&hashSearch)) {
  1598.     if (hdrPtr->fileID.type == FSIO_LCL_FILE_STREAM &&
  1599.         hdrPtr->fileID.major == domain) {
  1600.         register Fsio_FileIOHandle *handlePtr =
  1601.             (Fsio_FileIOHandle *) hdrPtr;
  1602.         Fsconsist_FetchDirtyBlocks(&handlePtr->consist, invalidate);
  1603.     }
  1604.     Fsutil_HandleUnlock(hdrPtr);
  1605.     }
  1606. }
  1607.  
  1608. /*
  1609.  * ----------------------------------------------------------------------------
  1610.  *
  1611.  * Fsconsist_FetchDirtyBlocks --
  1612.  *
  1613.  *      Fetch dirty blocks back from the last writer of the file.
  1614.  *    This is called when a domain is being detached (dis-mounted)
  1615.  *    and we want all dirty data to be written back first.
  1616.  *
  1617.  * Results:
  1618.  *    None.
  1619.  *
  1620.  * Side effects:
  1621.  *    If the last writer doesn't have the file actively open, then it is
  1622.  *    no longer the last writer and it is deleted from the client list.
  1623.  *
  1624.  * ----------------------------------------------------------------------------
  1625.  *
  1626.  */
  1627. ENTRY void
  1628. Fsconsist_FetchDirtyBlocks(consistPtr, invalidate)
  1629.     Fsconsist_Info *consistPtr;    /* Consistency state for file. */
  1630.     Boolean    invalidate;    /* If TRUE the client is told to invalidate
  1631.                  * after writing back the blocks */
  1632. {
  1633.     register    Fsconsist_ClientInfo    *clientPtr;
  1634.     register    Fsconsist_ClientInfo    *nextClientPtr;
  1635.  
  1636.     Fsutil_HandleUnlock(consistPtr->hdrPtr);
  1637.     LOCK_MONITOR;
  1638.  
  1639.     /*
  1640.      * Make sure that no one else is in the middle of performing cache
  1641.      * consistency on this handle.  If so wait until they are done.
  1642.      */
  1643.     while (consistPtr->flags & FS_CONSIST_IN_PROGRESS) {
  1644.     (void) Sync_Wait(&consistPtr->consistDone, FALSE);
  1645.     }
  1646.     /*
  1647.      * See if there are any dirty blocks to fetch.
  1648.      */
  1649.     if (consistPtr->lastWriter == -1 ||
  1650.     consistPtr->lastWriter == rpc_SpriteID) {
  1651.         UNLOCK_MONITOR;
  1652.     Fsutil_HandleLock(consistPtr->hdrPtr);
  1653.     return;
  1654.     }
  1655.     consistPtr->flags = FS_CONSIST_IN_PROGRESS;
  1656.  
  1657.     /*
  1658.      * There is a last writer.  In this case the only thing on the list is
  1659.      * the client that is the last writer because we know the domain for
  1660.      * the file is in-active.
  1661.      */
  1662.     nextClientPtr = (Fsconsist_ClientInfo *)List_First(&consistPtr->clientList);
  1663.     while (!List_IsAtEnd(&consistPtr->clientList, (List_Links *)nextClientPtr)){
  1664.     clientPtr = nextClientPtr;
  1665.     clientPtr->locked = FALSE;
  1666.     nextClientPtr = (Fsconsist_ClientInfo *)List_Next((List_Links *)clientPtr);
  1667.     if (!List_IsAtEnd(&consistPtr->clientList,(List_Links *)nextClientPtr)){
  1668.         nextClientPtr->locked = TRUE;
  1669.     }
  1670.     if (clientPtr->clientID != consistPtr->lastWriter) {
  1671.         Fsutil_HandleLock(consistPtr->hdrPtr);
  1672.         consistPtr->flags = 0;
  1673.         UNLOCK_MONITOR;
  1674.         panic("Fsconsist_FetchDirtyBlocks: Non last writer in list.\n");
  1675.         return;
  1676.     } else if (clientPtr->use.write > 0) {
  1677.         /*
  1678.          * The client has it actively open for writing.  In this case don't
  1679.          * do anything because he can have more dirty blocks anyway.
  1680.          */
  1681.     } else {
  1682.         register int flags = FSCONSIST_WRITE_BACK_BLOCKS;
  1683.         if (invalidate) {
  1684.         flags |= FSCONSIST_INVALIDATE_BLOCKS;
  1685.         }
  1686.         ClientCommand(consistPtr, clientPtr, flags);
  1687. #ifdef SOSP91
  1688.         /*  This is a weird one XXX */
  1689.         SOSP_ADD_CONSIST_ACTION_TRACE(rpc_SpriteID, clientPtr->clientID, consistPtr->hdrPtr->fileID, flags);
  1690. #endif SOSP91
  1691.         (void)EndConsistency(consistPtr);
  1692.     }
  1693.     }
  1694.     consistPtr->flags = 0;
  1695.     UNLOCK_MONITOR;
  1696.     Fsutil_HandleLock(consistPtr->hdrPtr);
  1697.     return;
  1698. }
  1699.  
  1700. /*
  1701.  * The consistency messages are issued in two parts.  In the first phase
  1702.  * the server issues all the clients commands, but the clients return
  1703.  * an RPC reply immediately and schedule ProcessConsist in the background
  1704.  * to actually effect the cache consistency.  The second phase consists
  1705.  * of the server waiting around for a return RPC by the client that
  1706.  * indicates that it is done.
  1707.  */
  1708. void    ProcessConsist();
  1709. void    ProcessConsistReply();
  1710. /*
  1711.  * Consist message information.
  1712.  */
  1713. typedef struct ConsistItem {
  1714.     int        serverID;
  1715.     ConsistMsg args;
  1716. } ConsistItem;
  1717.  
  1718. /*
  1719.  * ----------------------------------------------------------------------------
  1720.  *
  1721.  * ClientCommand --
  1722.  *
  1723.  *    Send an rpc to a client telling him to perform some cache 
  1724.  *    consistency operation.  Also put the client onto a list of 
  1725.  *    outstanding cache consistency messages.
  1726.  *
  1727.  * Results:
  1728.  *    The status from the RPC.
  1729.  *
  1730.  * Side effects:
  1731.  *    All locks except the consistency-in-progress lock are released
  1732.  *    during the call back to the client.  This allows operations like
  1733.  *    write-backs and unrelated closes of the file to complete.
  1734.  *    However, this means that the state of a file can change considerably
  1735.  *    during a call-back.  Of concern to routines in this file is that
  1736.  *    client list entries might get deleted, so LIST_FORALL doesn't work.
  1737.  *    Callers of ClientCommand have to be coded to reflect this.
  1738.  *
  1739.  * ----------------------------------------------------------------------------
  1740.  *
  1741.  */
  1742.  
  1743. INTERNAL void
  1744. ClientCommand(consistPtr, clientPtr, flags)
  1745.     register Fsconsist_Info *consistPtr;    /* Consistency state of file */
  1746.     Fsconsist_ClientInfo *clientPtr;    /* State of other client's cache */
  1747.     int            flags;        /* Command for the other client */
  1748. {
  1749.     Rpc_Storage        storage;
  1750.     ConsistMsg        consistRpc;
  1751.     ReturnStatus    status;
  1752.     ConsistMsgInfo    *msgPtr;
  1753.     int            numRefusals;
  1754.  
  1755.     if (clientPtr->clientID == rpc_SpriteID) {
  1756.     /*
  1757.      * Don't issue commands to ourselves (the server) because the commands
  1758.      * issued to the other clients (write-back, invalidate, etc.) will
  1759.      * all result in a consistent server cache anyway.
  1760.      */
  1761.     if (flags & FSCONSIST_INVALIDATE_BLOCKS) {
  1762.         /*
  1763.          * If we told ourselves to invalidate the file then mark us
  1764.          * as not caching the file.
  1765.          */
  1766.         clientPtr->cached = FALSE;
  1767.     }
  1768.     if (flags & FSCONSIST_WRITE_BACK_BLOCKS) {
  1769.         /*
  1770.          * We already have the most recent blocks.
  1771.          */
  1772.         consistPtr->lastWriter = -1;
  1773.     }
  1774.     if (clientPtr->use.ref == 0 && 
  1775.         consistPtr->lastWriter != clientPtr->clientID) {
  1776.         FSCACHE_DEBUG_PRINT1("ClientCommand: Removing %d ",
  1777.                     clientPtr->clientID);
  1778.         REMOVE_CLIENT(clientPtr);
  1779.     }
  1780.     return;
  1781.     }
  1782.     /*
  1783.      * Map to the client's view of the file (i.e. remote).
  1784.      */
  1785.     consistRpc.fileID = consistPtr->hdrPtr->fileID;
  1786.     if (consistRpc.fileID.type != FSIO_LCL_FILE_STREAM) {
  1787.         panic("ClientCommand, bad stream type <%d>\n",
  1788.             consistRpc.fileID.type);
  1789.     } else {
  1790.     consistRpc.fileID.type = FSIO_RMT_FILE_STREAM;
  1791.     }
  1792.     /*
  1793.      * The openTimeStamp lets the client catch races between this message
  1794.      * and the reply to an open it may be making at the same time.
  1795.      */
  1796.     consistRpc.flags = flags;
  1797.     consistRpc.openTimeStamp = clientPtr->openTimeStamp;
  1798.     consistRpc.version =
  1799.     ((Fsio_FileIOHandle *)consistPtr->hdrPtr)->cacheInfo.version;
  1800.  
  1801.     storage.requestParamPtr = (Address) &consistRpc;
  1802.     storage.requestParamSize = sizeof(ConsistMsg);
  1803.     storage.requestDataPtr = (Address) NIL;
  1804.     storage.requestDataSize = 0;
  1805.  
  1806.     storage.replyParamPtr = (Address) NIL;
  1807.     storage.replyParamSize = 0;
  1808.     storage.replyDataPtr = (Address) NIL;
  1809.     storage.replyDataSize = 0;
  1810.  
  1811.     /*
  1812.      * Put the client onto the list of outstanding cache consistency
  1813.      * messages.
  1814.      */
  1815.  
  1816.     msgPtr = (ConsistMsgInfo *) malloc(sizeof(ConsistMsgInfo));
  1817.     msgPtr->clientID = clientPtr->clientID;
  1818.     msgPtr->flags = consistRpc.flags;
  1819.     List_Insert((List_Links *) msgPtr, LIST_ATREAR(&consistPtr->msgList));
  1820.  
  1821.     /*
  1822.      * Have to release this monitor during the call-back so that
  1823.      * an unrelated close can complete its call to Fsconsist_Close.
  1824.      * Alternatives are to fix the consistency call-back RPC stubs
  1825.      * so they don't lock the handle.
  1826.      */
  1827.     if ((consistPtr->flags & FS_CONSIST_IN_PROGRESS) == 0) {
  1828.     panic( "Client CallBack - consist flag not set\n");
  1829.     }
  1830.     UNLOCK_MONITOR;
  1831.     numRefusals = 0;
  1832.     while ( TRUE ) {
  1833.     /*
  1834.      * Send the rpc to the client.  The client will return FAILURE if the
  1835.      * open that we are talking about hasn't returned to the client yet.
  1836.      */
  1837.     status = Rpc_Call(clientPtr->clientID, RPC_FS_CONSIST, &storage);
  1838.     if (status != FAILURE) {
  1839.         break;
  1840.     } else {
  1841.         numRefusals++;
  1842.         if (numRefusals > 30) {
  1843.         printf("Client %d dropped 30 %s requests for \"%s\" <%d,%d>\n",
  1844.                 clientPtr->clientID, ConsistType(flags),
  1845.                 Fsutil_HandleName(consistPtr->hdrPtr),
  1846.                 consistRpc.fileID.major, consistRpc.fileID.minor);
  1847.         consistRpc.flags |= FSCONSIST_DEBUG;
  1848.         numRefusals = 0;
  1849.         } else {
  1850.         consistRpc.flags &= ~FSCONSIST_DEBUG;
  1851.         }
  1852.     }
  1853.     }
  1854.     if (status != SUCCESS) {
  1855.     /*
  1856.      * Couldn't post call-back to the client.
  1857.      */
  1858.     int ref, write, exec;
  1859.     int clientID = clientPtr->clientID;
  1860.     printf("ClientCommand, %s msg to client %d file \"%s\" <%d,%d> failed %x\n",
  1861.         ConsistType(flags), clientID, Fsutil_HandleName(consistPtr->hdrPtr),
  1862.         consistRpc.fileID.major, consistRpc.fileID.minor, status);
  1863.     if (status == RPC_TIMEOUT || status == FS_STALE_HANDLE) {
  1864.         /*
  1865.          * If its really down, then nuke it from the
  1866.          * list of clients using the file.
  1867.          */
  1868.         Fsconsist_Kill(consistPtr, clientPtr->clientID, &ref, &write, &exec);
  1869.         printf("\tClient state killed: %d refs %d write %d exec\n",
  1870.             ref, write, exec);
  1871.     } else {
  1872.         /*
  1873.          * Just nuke the message from the list so EndConsistency
  1874.          * terminates.  Sometimes the callback fails because the
  1875.          * host is still booting and hasn't enabled its RPC service yet.
  1876.          */
  1877.         List_Remove((List_Links *)msgPtr);
  1878.         free((Address)msgPtr);
  1879.     }
  1880.     }
  1881.     LOCK_MONITOR;
  1882. }
  1883.  
  1884. /*
  1885.  *----------------------------------------------------------------------
  1886.  *
  1887.  * Fsconsist_RpcConsist --
  1888.  *
  1889.  *    Service stub for RPC_FS_CONSIST.  This is executed on a filesystem
  1890.  *    client in response to a cache consistency command.  This schedules
  1891.  *    a call to ProcessConsist and returns a reply to the server.
  1892.  *    If, by remote chance, the message concerns an in-progress open
  1893.  *    that hasn't yet completed, we just return an error code to the
  1894.  *    server so that it will re-send its request after we know about
  1895.  *    the open.
  1896.  *
  1897.  * Results:
  1898.  *    SUCCESS.
  1899.  *
  1900.  * Side effects:
  1901.  *    Add work to the queue for the client consistency process.
  1902.  *
  1903.  *----------------------------------------------------------------------
  1904.  */
  1905. /*ARGSUSED*/
  1906. ReturnStatus
  1907. Fsconsist_RpcConsist(srvToken, clientID, command, storagePtr)
  1908.     ClientData srvToken;    /* Handle on server process passed to
  1909.                  * Rpc_Reply */
  1910.     int clientID;        /* ID of server controlling the file */
  1911.     int command;        /* Command identifier */
  1912.     Rpc_Storage *storagePtr;    /* The request fields refer to the request
  1913.                  * buffers and also indicate the exact amount
  1914.                  * of data in the request buffers.  The reply
  1915.                  * fields are initialized to NIL for the
  1916.                  * pointers and 0 for the lengths.  This can
  1917.                  * be passed to Rpc_Reply */
  1918. {
  1919.     register ConsistMsg        *consistArgPtr;
  1920.     register ConsistItem    *consistPtr;
  1921.     register Fsrmt_FileIOHandle    *rmtHandlePtr;
  1922.     register ReturnStatus    status;
  1923.  
  1924.     consistArgPtr = (ConsistMsg *)storagePtr->requestParamPtr;
  1925.     if (consistArgPtr->fileID.type != FSIO_RMT_FILE_STREAM) {
  1926.     printf("Fsconsist_RpcConsist bad fileID <%d,%d,%d,%d> from client %d\n",
  1927.             consistArgPtr->fileID.type, consistArgPtr->fileID.serverID,
  1928.             consistArgPtr->fileID.major, consistArgPtr->fileID.minor,
  1929.             clientID);
  1930.     return(FAILURE);
  1931.     }
  1932.     /*
  1933.      * This fetch locks the handle.  In earlier versions of the kernel
  1934.      * this could cause deadlock.  This may still be true.  3/9/88.
  1935.      */
  1936.     rmtHandlePtr = Fsutil_HandleFetchType(Fsrmt_FileIOHandle,
  1937.                       &consistArgPtr->fileID);
  1938.     if (rmtHandlePtr == (Fsrmt_FileIOHandle *)NIL) {
  1939.     if (Fsprefix_OpenInProgress(&consistArgPtr->fileID) == 0) {
  1940.         status = FS_STALE_HANDLE;
  1941. #ifdef CONSIST_DEBUG
  1942.         printf("Fsconsist_RpcConsist: <%d,%d> %s msg from %d dropped: %s\n",
  1943.             consistArgPtr->fileID.major,
  1944.             consistArgPtr->fileID.minor,
  1945.             ConsistType(consistArgPtr->flags),
  1946.             consistArgPtr->fileID.serverID,
  1947.             "no handle");
  1948. #endif /* CONSIST_DEBUG */
  1949.     } else {
  1950.         /*
  1951.          * A consistency message has arrived from an open from which
  1952.          * we haven't received the reply.  Return FAILURE to force
  1953.          * the server to resend and give the open reply a chance
  1954.          * of getting to us.  This is the "open/consistency race".
  1955.          */
  1956.         status = FAILURE;
  1957.     }
  1958.     } else if (rmtHandlePtr->openTimeStamp != consistArgPtr->openTimeStamp) {
  1959.     if ((rmtHandlePtr->cacheInfo.version == consistArgPtr->version) &&
  1960.         ((consistArgPtr->flags & (FSCONSIST_DELETE_FILE|
  1961.                      FSCONSIST_WRITE_BACK_BLOCKS)) == 0)) {
  1962.         /*
  1963.          * We have the same version as the server, but there has been
  1964.          * more open traffic than we realize.  If this is any command
  1965.          * except a write-back or delete (like return-attrs), then
  1966.          * we'll do it.
  1967.          */
  1968.         status = SUCCESS;
  1969.     } else if (Fsprefix_OpenInProgress(&consistArgPtr->fileID) == 0) {
  1970.         status = FS_STALE_HANDLE;
  1971.         printf("Fsconsist_RpcConsist: <%d,%d> %s msg from %d timestamp %d not %d\n\t version %d and %d, returning stale handle\n",
  1972.             consistArgPtr->fileID.major,
  1973.             consistArgPtr->fileID.minor,
  1974.             ConsistType(consistArgPtr->flags),
  1975.             consistArgPtr->fileID.serverID,
  1976.             consistArgPtr->openTimeStamp, rmtHandlePtr->openTimeStamp,
  1977.             consistArgPtr->version, rmtHandlePtr->cacheInfo.version);
  1978.     } else {
  1979.         /*
  1980.          * Timestamp mis-match and an open in progress.
  1981.          * Possible open/consistency race.
  1982.          */
  1983.         status = FAILURE;
  1984.     }
  1985.     } else {
  1986.     status = SUCCESS;
  1987.     }
  1988.  
  1989.     if (rmtHandlePtr != (Fsrmt_FileIOHandle *)NIL) {
  1990.     Fsutil_HandleRelease(rmtHandlePtr, TRUE);
  1991.     }
  1992.     if (status == SUCCESS) {
  1993.     /*
  1994.      * This is a message corresponding to our current notion of the
  1995.      * file.  Pass the message to a consistency handler process.
  1996.      */
  1997.     consistPtr = (ConsistItem *) malloc(sizeof(ConsistItem));
  1998.     consistPtr->serverID = clientID;
  1999.     consistPtr->args = *consistArgPtr;
  2000.     Proc_CallFunc(ProcessConsist, (ClientData) consistPtr, 0);
  2001.     } else if (consistArgPtr->flags & FSCONSIST_DEBUG) {
  2002.     printf("Fsconsist_RpcConsist: <%d,%d> Lots of %s msgs dropped: %s\n",
  2003.             consistArgPtr->fileID.major,
  2004.             consistArgPtr->fileID.minor,
  2005.             ConsistType(consistArgPtr->flags),
  2006.             (status == FS_STALE_HANDLE) ? "stale handle" :
  2007.                           "open in progress");
  2008.     }
  2009.     Rpc_Reply(srvToken, status, storagePtr, (int(*)())NIL, (ClientData)NIL);
  2010.     return(SUCCESS);
  2011. }
  2012.  
  2013.  
  2014. /*
  2015.  * ----------------------------------------------------------------------------
  2016.  *
  2017.  * ProcessConsist --
  2018.  *
  2019.  *    Process a cache consistency request from the server.  This
  2020.  *    is called in the background as the result of a request from
  2021.  *    the server.  This routine is a thin wrapper around a routine
  2022.  *    in the cache module that does all the work.
  2023.  *
  2024.  * Results:
  2025.  *    None.
  2026.  *
  2027.  * Side effects:
  2028.  *    See Fscache_Consist.
  2029.  *
  2030.  * ----------------------------------------------------------------------------
  2031.  *
  2032.  */
  2033. void
  2034. ProcessConsist(data, callInfoPtr)
  2035.     ClientData        data;
  2036.     Proc_CallInfo    *callInfoPtr;
  2037. {
  2038.     register Fsrmt_FileIOHandle     *handlePtr;
  2039.     ReturnStatus        status;
  2040.     Rpc_Storage            storage;
  2041.     ConsistReply        reply;
  2042.     register    ConsistItem    *consistPtr;
  2043.  
  2044.     consistPtr = (ConsistItem *) data;
  2045.     callInfoPtr->interval = 0;
  2046.  
  2047.     handlePtr = Fsutil_HandleFetchType(Fsrmt_FileIOHandle,
  2048.                        &consistPtr->args.fileID);
  2049.     if (handlePtr == (Fsrmt_FileIOHandle *)NIL) {
  2050.     printf("ProcessConsist: no handle <%d, %d, %d, %d>\n",
  2051.             consistPtr->args.fileID.type,
  2052.             consistPtr->args.fileID.serverID,
  2053.             consistPtr->args.fileID.major,
  2054.             consistPtr->args.fileID.minor);
  2055.     return;
  2056.     }
  2057.     Fsutil_HandleUnlock(handlePtr);
  2058.  
  2059.     FSCACHE_DEBUG_PRINT2("ProcessConsist: Got %s request for file %d\n", 
  2060.     ConsistType(consistPtr->args.flags), handlePtr->rmt.hdr.fileID.minor);
  2061.  
  2062.     /*
  2063.      * Process the request under the per file cache lock.
  2064.      */
  2065.     reply.status = Fscache_Consist(&handlePtr->cacheInfo,
  2066.             consistPtr->args.flags, &reply.cachedAttr);
  2067. #ifdef CONSIST_DEBUG
  2068.     if (fsTraceConsistMinor == handlePtr->rmt.hdr.fileID.minor) {
  2069.     printf(
  2070.     "ProcessConsist, %s msg for file \"%s\" <%d,%d> version %d status %x\n",
  2071.         ConsistType(consistPtr->args.flags), 
  2072.         Fsutil_HandleName(handlePtr),
  2073.         handlePtr->rmt.hdr.fileID.major, handlePtr->rmt.hdr.fileID.minor,
  2074.         consistPtr->args.version, reply.status);
  2075.     }
  2076. #endif /* CONSIST_DEBUG */
  2077.  
  2078.     FSCACHE_DEBUG_PRINT2("Returning: mod (%d), acc (%d),",
  2079.                reply.cachedAttr.modifyTime,
  2080.                reply.cachedAttr.accessTime);
  2081.     FSCACHE_DEBUG_PRINT2(" first (%d), last (%d)\n",
  2082.                reply.cachedAttr.firstByte, reply.cachedAttr.lastByte);
  2083.     reply.fileID = handlePtr->rmt.hdr.fileID;
  2084.     reply.fileID.type = FSIO_LCL_FILE_STREAM;
  2085.     Fsutil_HandleRelease(handlePtr, FALSE);
  2086.     /*
  2087.      * Set up the reply buffer.
  2088.      */
  2089.     storage.requestParamPtr = (Address)&reply;
  2090.     storage.requestParamSize = sizeof(ConsistReply);
  2091.     storage.requestDataPtr = (Address)NIL;
  2092.     storage.requestDataSize = 0;
  2093.     storage.replyParamPtr = (Address)NIL;
  2094.     storage.replyParamSize = 0;
  2095.     storage.replyDataPtr = (Address)NIL;
  2096.     storage.replyDataSize = 0;
  2097.  
  2098.     for ( ; ; ) {
  2099.     status = Rpc_Call(consistPtr->serverID, RPC_FS_CONSIST_REPLY, &storage);
  2100.     if (status != SUCCESS) {
  2101.         printf("Got error (%x) from consist reply on <%d,%d>\n", status,
  2102.         reply.fileID.major, reply.fileID.minor);
  2103.     }
  2104.     if (status != RPC_TIMEOUT) {
  2105.         break;
  2106.     }
  2107.     }
  2108.     free((Address)consistPtr);
  2109. }
  2110.  
  2111.  
  2112. /*
  2113.  *----------------------------------------------------------------------
  2114.  *
  2115.  * Fsconsist_RpcConsistReply --
  2116.  *
  2117.  *    Service stub for RPC_FS_CONSIST_REPLY.  This RPC indicates that
  2118.  *    the client has completed the consistency actions we previously
  2119.  *    asked it to perform.
  2120.  *
  2121.  * Results:
  2122.  *    SUCCESS, unless we don't like the fileID specified by the client.
  2123.  *
  2124.  * Side effects:
  2125.  *    See ProcessConsistReply.
  2126.  *
  2127.  *----------------------------------------------------------------------
  2128.  */
  2129. /*ARGSUSED*/
  2130. ReturnStatus
  2131. Fsconsist_RpcConsistReply(srvToken, clientID, command, storagePtr)
  2132.     ClientData srvToken;    /* Handle on server process passed to
  2133.                  * Rpc_Reply */
  2134.     int clientID;        /* Sprite ID of client host */
  2135.     int command;        /* Command identifier */
  2136.     Rpc_Storage *storagePtr;    /* The request fields refer to the request
  2137.                  * buffers and also indicate the exact amount
  2138.                  * of data in the request buffers.  The reply
  2139.                  * fields are initialized to NIL for the
  2140.                  * pointers and 0 for the lengths.  This can
  2141.                  * be passed to Rpc_Reply */
  2142. {
  2143.     Fsio_FileIOHandle    *handlePtr;
  2144.     ConsistReply    *replyPtr;
  2145.  
  2146.     replyPtr = (ConsistReply *) storagePtr->requestParamPtr;
  2147.     if (replyPtr->fileID.type != FSIO_LCL_FILE_STREAM) {
  2148.     printf("Fsconsist_RpcConsistReply: bad fileID <%d,%d,%d,%d> from client %d\n",
  2149.         replyPtr->fileID.type, replyPtr->fileID.serverID,
  2150.         replyPtr->fileID.major, replyPtr->fileID.minor, clientID);
  2151.         return(GEN_INVALID_ARG);
  2152.     }
  2153.     handlePtr = Fsutil_HandleFetchType(Fsio_FileIOHandle, &(replyPtr->fileID));
  2154.     if (handlePtr == (Fsio_FileIOHandle *) NIL) {
  2155.     printf("Fsconsist_RpcConsistReply: no handle <%d,%d> for client %d\n",
  2156.         replyPtr->fileID.major, replyPtr->fileID.minor, clientID);
  2157.     return(FS_STALE_HANDLE);
  2158.     }
  2159.     /*
  2160.      * Unlock the handle to prevent deadlock if this RPC
  2161.      * arrives as ClientRemoveCallback is attempting to relock
  2162.      * the handle on its way out of the per-file consistency monitor.
  2163.      * (This can only happen if the server 'kills' the client state and so
  2164.      * aborts the cache consistency wait before this arrives.)
  2165.      * Ordinarily this RPC arrives as it is waiting with the monitor
  2166.      * unlocked.  The handle lock is not needed anyway because once we have
  2167.      * successfully fetched the handle it won't go away on us.  Furthermore,
  2168.      * ProcessConsistReply can handle it if the client state has been killed.
  2169.      */
  2170.     Fsutil_HandleUnlock(handlePtr);
  2171.     ProcessConsistReply(&handlePtr->consist, clientID, replyPtr);
  2172.     Fsutil_HandleRelease(handlePtr, FALSE);
  2173.     Rpc_Reply(srvToken, SUCCESS, storagePtr, 
  2174.           (int (*)())NIL, (ClientData)NIL);
  2175.     return(SUCCESS);
  2176. }
  2177.  
  2178.  
  2179. /*
  2180.  *----------------------------------------------------------------------
  2181.  *
  2182.  * ProcessConsistReply --
  2183.  *
  2184.  *    Process the reply sent by the client for the given handle.
  2185.  *    This updates the caching state of the client, and it may
  2186.  *    also update the handle attributes based on information returned
  2187.  *    from the client.  This is call after the client has completed
  2188.  *    the cache consistency actions we previously requested of it.
  2189.  *
  2190.  * Results:
  2191.  *    None.
  2192.  *
  2193.  * Side effects:
  2194.  *    Element deleted from the list of outstanding client consist 
  2195.  *    messages.  Also if the message was for invalidation then the
  2196.  *    client list entry is marked as non-cacheable.  IMPORTANT:
  2197.  *    client list entry may be REMOVED here which prevents safe
  2198.  *    use of LIST_FORALL iteration over the client list by any
  2199.  *    routine that calls ClientCommand (which eventually gets us called)
  2200.  *
  2201.  *----------------------------------------------------------------------
  2202.  */
  2203. ENTRY void
  2204. ProcessConsistReply(consistPtr, clientID, replyPtr)
  2205.     Fsconsist_Info        *consistPtr;    /* File to process reply for*/
  2206.     int                clientID;    /* Client who sent us the 
  2207.                          * reply. */
  2208.     register    ConsistReply    *replyPtr;    /* The reply that was sent. */
  2209. {
  2210.     register    ConsistMsgInfo        *msgPtr;
  2211.     register    Fsconsist_ClientInfo     *clientPtr;
  2212.     Boolean                found = FALSE;
  2213.     Fsio_FileIOHandle            *handlePtr;
  2214.  
  2215.     LOCK_MONITOR;
  2216.  
  2217.     /*
  2218.      * Find the client in the list of pending messages.  Notify the
  2219.      * opening process after all the clients have responded.
  2220.      */
  2221.     LIST_FORALL(&(consistPtr->msgList), (List_Links *) msgPtr) {
  2222.     if (msgPtr->clientID == clientID) {
  2223.         List_Remove((List_Links *) msgPtr);
  2224.         found = TRUE;
  2225.         break;
  2226.     }
  2227.     }
  2228.     if (List_IsEmpty(&(consistPtr->msgList))) {
  2229.     Sync_Broadcast(&consistPtr->repliesIn);
  2230.     }
  2231.     if (!found) {
  2232.     /*
  2233.      * We don't know about this cache consistency action by the
  2234.      * client, perhaps because we concluded it was down and
  2235.      * killed our state about it.  It is also possible that it is an
  2236.      * old message from the client, probably queued in the network
  2237.      * interface across a reboot or from a gateway.
  2238.      */
  2239.     UNLOCK_MONITOR;
  2240.     return;
  2241.     }
  2242. #ifdef CONSIST_DEBUG
  2243.     if (fsTraceConsistMinor == consistPtr->hdrPtr->fileID.minor) {
  2244.     printf(
  2245.     "ConsistReply, %s msg for file \"%s\" <%d,%d> writer %d status %x\n",
  2246.         ConsistType(msgPtr->flags), 
  2247.         Fsutil_HandleName(consistPtr->hdrPtr),
  2248.         consistPtr->hdrPtr->fileID.major, consistPtr->hdrPtr->fileID.minor,
  2249.         consistPtr->lastWriter,
  2250.         replyPtr->status);
  2251.     }
  2252. #endif /* CONSIST_DEBUG */
  2253.     if (replyPtr->status != SUCCESS) {
  2254.     printf("ProcessConsist: %s request failed <%x> file \"%s\" <%d,%d>\n",
  2255.         ConsistType(msgPtr->flags), replyPtr->status,
  2256.         Fsutil_HandleName(consistPtr->hdrPtr),
  2257.         consistPtr->hdrPtr->fileID.major,
  2258.         consistPtr->hdrPtr->fileID.minor);
  2259.     consistPtr->flags |= FS_CONSIST_ERROR;
  2260.     } else {
  2261.     if ((msgPtr->flags & FSCONSIST_WRITE_BACK_BLOCKS) &&
  2262.         (consistPtr->lastWriter == clientID)) {
  2263.         /*
  2264.          * We just got the most recent blocks so we don't care who the
  2265.          * last writer is anymore.
  2266.          */
  2267.         consistPtr->lastWriter = -1;
  2268.     }
  2269.     /*
  2270.      * Look for client list entry that match the client, and update
  2271.      * its state to reflect the consistency action by the client.
  2272.      * Because we've release the monitor lock during the previous
  2273.      * call-back, an unrelated action may have removed the client
  2274.      * from the list - no big deal.
  2275.      */
  2276.     LIST_FORALL(&(consistPtr->clientList), (List_Links *) clientPtr) {
  2277.         if (clientPtr->clientID == clientID) {
  2278.         handlePtr = (Fsio_FileIOHandle *)consistPtr->hdrPtr;
  2279.         if (msgPtr->flags & (FSCONSIST_WRITE_BACK_BLOCKS |
  2280.                      FSCONSIST_WRITE_BACK_ATTRS)) {
  2281.             Fscache_UpdateAttrFromClient(clientID,
  2282.                 &handlePtr->cacheInfo, &replyPtr->cachedAttr);
  2283.             (void) Fsdm_UpdateDescAttr(handlePtr, 
  2284.                     &handlePtr->cacheInfo.attr, -1);
  2285.         }
  2286.         if (clientPtr->use.ref == 0 &&
  2287.             consistPtr->lastWriter != clientID) {
  2288.             REMOVE_CLIENT(clientPtr);
  2289.         } else if (msgPtr->flags & FSCONSIST_INVALIDATE_BLOCKS) {
  2290.             clientPtr->cached = FALSE;
  2291.         }
  2292.         break;
  2293.         }
  2294.     }
  2295.     }
  2296.     free((Address) msgPtr);
  2297.  
  2298.     UNLOCK_MONITOR;
  2299. }
  2300.  
  2301. /*
  2302.  *----------------------------------------------------------------------
  2303.  *
  2304.  * ConsistType --
  2305.  *
  2306.  *    Utility routine to map from consistency flags to a printable string.
  2307.  *
  2308.  * Results:
  2309.  *    A pointer to a printable string.
  2310.  *
  2311.  * Side effects:
  2312.  *    None.
  2313.  *
  2314.  *----------------------------------------------------------------------
  2315.  */
  2316.  
  2317. char *
  2318. ConsistType(flags)
  2319.     int flags;        /* Cache consistency message flags */
  2320. {
  2321.     register char *result;
  2322.     switch (flags & ~FSCONSIST_DEBUG) {
  2323.     case FSCONSIST_WRITE_BACK_BLOCKS:
  2324.         result = "write-back";
  2325.         break;
  2326.     case FSCONSIST_INVALIDATE_BLOCKS:
  2327.         result = "invalidate";
  2328.         break;
  2329.     case (FSCONSIST_WRITE_BACK_BLOCKS|FSCONSIST_INVALIDATE_BLOCKS):
  2330.         result = "write-back & invalidate";
  2331.         break;
  2332.     case FSCONSIST_DELETE_FILE:
  2333.         result = "delete";
  2334.         break;
  2335.     case FSCONSIST_WRITE_BACK_ATTRS:
  2336.         result = "return-attrs";
  2337.         break;
  2338.     default:
  2339.         result = "UNKNOWN";
  2340.         break;
  2341.     }
  2342.     return(result);
  2343. }
  2344.